mirror of https://github.com/zulip/zulip.git
actions: Split out zerver.actions.create_user.
Signed-off-by: Anders Kaseorg <anders@zulip.com>
This commit is contained in:
parent
5fcbc412cf
commit
cbad5739ab
|
@ -32,6 +32,11 @@ from analytics.models import (
|
||||||
UserCount,
|
UserCount,
|
||||||
installation_epoch,
|
installation_epoch,
|
||||||
)
|
)
|
||||||
|
from zerver.actions.create_user import (
|
||||||
|
do_activate_mirror_dummy_user,
|
||||||
|
do_create_user,
|
||||||
|
do_reactivate_user,
|
||||||
|
)
|
||||||
from zerver.actions.invites import (
|
from zerver.actions.invites import (
|
||||||
do_invite_users,
|
do_invite_users,
|
||||||
do_resend_user_invite_email,
|
do_resend_user_invite_email,
|
||||||
|
@ -40,12 +45,9 @@ from zerver.actions.invites import (
|
||||||
from zerver.actions.user_activity import update_user_activity_interval
|
from zerver.actions.user_activity import update_user_activity_interval
|
||||||
from zerver.actions.users import do_deactivate_user
|
from zerver.actions.users import do_deactivate_user
|
||||||
from zerver.lib.actions import (
|
from zerver.lib.actions import (
|
||||||
do_activate_mirror_dummy_user,
|
|
||||||
do_create_realm,
|
do_create_realm,
|
||||||
do_create_user,
|
|
||||||
do_mark_all_as_read,
|
do_mark_all_as_read,
|
||||||
do_mark_stream_messages_as_read,
|
do_mark_stream_messages_as_read,
|
||||||
do_reactivate_user,
|
|
||||||
do_update_message_flags,
|
do_update_message_flags,
|
||||||
)
|
)
|
||||||
from zerver.lib.create_user import create_user
|
from zerver.lib.create_user import create_user
|
||||||
|
|
|
@ -5,7 +5,7 @@ from django.utils.translation import gettext as _
|
||||||
|
|
||||||
from corporate.lib.stripe import LicenseLimitError, get_latest_seat_count
|
from corporate.lib.stripe import LicenseLimitError, get_latest_seat_count
|
||||||
from corporate.models import get_current_plan_by_realm
|
from corporate.models import get_current_plan_by_realm
|
||||||
from zerver.lib.actions import send_message_to_signup_notification_stream
|
from zerver.actions.create_user import send_message_to_signup_notification_stream
|
||||||
from zerver.lib.exceptions import InvitationError
|
from zerver.lib.exceptions import InvitationError
|
||||||
from zerver.models import Realm, get_system_bot
|
from zerver.models import Realm, get_system_bot
|
||||||
|
|
||||||
|
|
|
@ -81,15 +81,13 @@ from corporate.models import (
|
||||||
get_current_plan_by_realm,
|
get_current_plan_by_realm,
|
||||||
get_customer_by_realm,
|
get_customer_by_realm,
|
||||||
)
|
)
|
||||||
from zerver.actions.users import do_deactivate_user
|
from zerver.actions.create_user import (
|
||||||
from zerver.lib.actions import (
|
|
||||||
do_activate_mirror_dummy_user,
|
do_activate_mirror_dummy_user,
|
||||||
do_create_realm,
|
|
||||||
do_create_user,
|
do_create_user,
|
||||||
do_deactivate_realm,
|
|
||||||
do_reactivate_realm,
|
|
||||||
do_reactivate_user,
|
do_reactivate_user,
|
||||||
)
|
)
|
||||||
|
from zerver.actions.users import do_deactivate_user
|
||||||
|
from zerver.lib.actions import do_create_realm, do_deactivate_realm, do_reactivate_realm
|
||||||
from zerver.lib.test_classes import ZulipTestCase
|
from zerver.lib.test_classes import ZulipTestCase
|
||||||
from zerver.lib.timestamp import datetime_to_timestamp, timestamp_to_datetime
|
from zerver.lib.timestamp import datetime_to_timestamp, timestamp_to_datetime
|
||||||
from zerver.lib.utils import assert_is_not_none
|
from zerver.lib.utils import assert_is_not_none
|
||||||
|
|
|
@ -33,9 +33,9 @@ import zulip
|
||||||
|
|
||||||
from scripts.lib.zulip_tools import BOLDRED, ENDC
|
from scripts.lib.zulip_tools import BOLDRED, ENDC
|
||||||
from tools.lib.test_script import prepare_puppeteer_run
|
from tools.lib.test_script import prepare_puppeteer_run
|
||||||
|
from zerver.actions.create_user import do_create_user, notify_created_bot
|
||||||
from zerver.actions.streams import bulk_add_subscriptions
|
from zerver.actions.streams import bulk_add_subscriptions
|
||||||
from zerver.actions.user_settings import do_change_avatar_fields
|
from zerver.actions.user_settings import do_change_avatar_fields
|
||||||
from zerver.lib.actions import do_create_user, notify_created_bot
|
|
||||||
from zerver.lib.integrations import (
|
from zerver.lib.integrations import (
|
||||||
DOC_SCREENSHOT_CONFIG,
|
DOC_SCREENSHOT_CONFIG,
|
||||||
INTEGRATIONS,
|
INTEGRATIONS,
|
||||||
|
|
|
@ -31,13 +31,9 @@ with test_server_running(
|
||||||
):
|
):
|
||||||
# zerver imports should happen after `django.setup()` is run
|
# zerver imports should happen after `django.setup()` is run
|
||||||
# by the test_server_running decorator.
|
# by the test_server_running decorator.
|
||||||
|
from zerver.actions.create_user import do_create_user, do_reactivate_user
|
||||||
from zerver.actions.users import change_user_is_active
|
from zerver.actions.users import change_user_is_active
|
||||||
from zerver.lib.actions import (
|
from zerver.lib.actions import do_deactivate_realm, do_reactivate_realm
|
||||||
do_create_user,
|
|
||||||
do_deactivate_realm,
|
|
||||||
do_reactivate_realm,
|
|
||||||
do_reactivate_user,
|
|
||||||
)
|
|
||||||
from zerver.lib.test_helpers import reset_emails_in_zulip_realm
|
from zerver.lib.test_helpers import reset_emails_in_zulip_realm
|
||||||
from zerver.lib.users import get_api_key
|
from zerver.lib.users import get_api_key
|
||||||
from zerver.models import get_realm, get_user
|
from zerver.models import get_realm, get_user
|
||||||
|
|
|
@ -0,0 +1,566 @@
|
||||||
|
import datetime
|
||||||
|
from collections import defaultdict
|
||||||
|
from typing import Any, Dict, Iterable, List, Optional, Sequence, Set
|
||||||
|
|
||||||
|
import orjson
|
||||||
|
from django.conf import settings
|
||||||
|
from django.db import transaction
|
||||||
|
from django.utils.timezone import now as timezone_now
|
||||||
|
from django.utils.translation import gettext as _
|
||||||
|
from django.utils.translation import override as override_language
|
||||||
|
|
||||||
|
from analytics.lib.counts import COUNT_STATS, do_increment_logging_stat
|
||||||
|
from confirmation import settings as confirmation_settings
|
||||||
|
from zerver.actions.default_streams import get_default_streams_for_realm
|
||||||
|
from zerver.actions.invites import notify_invites_changed
|
||||||
|
from zerver.actions.message_send import internal_send_private_message, internal_send_stream_message
|
||||||
|
from zerver.actions.streams import bulk_add_subscriptions, send_peer_subscriber_events
|
||||||
|
from zerver.actions.user_groups import do_send_user_group_members_update_event
|
||||||
|
from zerver.actions.users import change_user_is_active, get_service_dicts_for_bot
|
||||||
|
from zerver.lib.avatar import avatar_url
|
||||||
|
from zerver.lib.create_user import create_user
|
||||||
|
from zerver.lib.email_notifications import enqueue_welcome_emails
|
||||||
|
from zerver.lib.mention import silent_mention_syntax_for_user
|
||||||
|
from zerver.lib.send_email import clear_scheduled_invitation_emails
|
||||||
|
from zerver.lib.stream_subscription import bulk_get_subscriber_peer_info
|
||||||
|
from zerver.lib.streams import get_signups_stream
|
||||||
|
from zerver.lib.user_counts import realm_user_count, realm_user_count_by_role
|
||||||
|
from zerver.lib.user_groups import get_system_user_group_for_user
|
||||||
|
from zerver.lib.users import format_user_row, get_api_key, user_profile_to_user_row
|
||||||
|
from zerver.models import (
|
||||||
|
DefaultStreamGroup,
|
||||||
|
Message,
|
||||||
|
PreregistrationUser,
|
||||||
|
Realm,
|
||||||
|
RealmAuditLog,
|
||||||
|
Recipient,
|
||||||
|
Stream,
|
||||||
|
Subscription,
|
||||||
|
UserGroup,
|
||||||
|
UserGroupMembership,
|
||||||
|
UserMessage,
|
||||||
|
UserProfile,
|
||||||
|
active_user_ids,
|
||||||
|
bot_owner_user_ids,
|
||||||
|
get_realm,
|
||||||
|
get_system_bot,
|
||||||
|
)
|
||||||
|
from zerver.tornado.django_api import send_event
|
||||||
|
|
||||||
|
if settings.BILLING_ENABLED:
|
||||||
|
from corporate.lib.stripe import update_license_ledger_if_needed
|
||||||
|
|
||||||
|
|
||||||
|
ONBOARDING_TOTAL_MESSAGES = 1000
|
||||||
|
ONBOARDING_UNREAD_MESSAGES = 20
|
||||||
|
ONBOARDING_RECENT_TIMEDELTA = datetime.timedelta(weeks=1)
|
||||||
|
|
||||||
|
|
||||||
|
def create_historical_user_messages(*, user_id: int, message_ids: List[int]) -> None:
|
||||||
|
# Users can see and interact with messages sent to streams with
|
||||||
|
# public history for which they do not have a UserMessage because
|
||||||
|
# they were not a subscriber at the time the message was sent.
|
||||||
|
# In order to add emoji reactions or mutate message flags for
|
||||||
|
# those messages, we create UserMessage objects for those messages;
|
||||||
|
# these have the special historical flag which keeps track of the
|
||||||
|
# fact that the user did not receive the message at the time it was sent.
|
||||||
|
for message_id in message_ids:
|
||||||
|
UserMessage.objects.create(
|
||||||
|
user_profile_id=user_id,
|
||||||
|
message_id=message_id,
|
||||||
|
flags=UserMessage.flags.historical | UserMessage.flags.read,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def send_message_to_signup_notification_stream(
|
||||||
|
sender: UserProfile, realm: Realm, message: str, topic_name: str = _("signups")
|
||||||
|
) -> None:
|
||||||
|
signup_notifications_stream = realm.get_signup_notifications_stream()
|
||||||
|
if signup_notifications_stream is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
with override_language(realm.default_language):
|
||||||
|
internal_send_stream_message(sender, signup_notifications_stream, topic_name, message)
|
||||||
|
|
||||||
|
|
||||||
|
def notify_new_user(user_profile: UserProfile) -> None:
|
||||||
|
user_count = realm_user_count(user_profile.realm)
|
||||||
|
sender_email = settings.NOTIFICATION_BOT
|
||||||
|
sender = get_system_bot(sender_email, user_profile.realm_id)
|
||||||
|
|
||||||
|
is_first_user = user_count == 1
|
||||||
|
if not is_first_user:
|
||||||
|
message = _("{user} just signed up for Zulip. (total: {user_count})").format(
|
||||||
|
user=silent_mention_syntax_for_user(user_profile), user_count=user_count
|
||||||
|
)
|
||||||
|
|
||||||
|
if settings.BILLING_ENABLED:
|
||||||
|
from corporate.lib.registration import generate_licenses_low_warning_message_if_required
|
||||||
|
|
||||||
|
licenses_low_warning_message = generate_licenses_low_warning_message_if_required(
|
||||||
|
user_profile.realm
|
||||||
|
)
|
||||||
|
if licenses_low_warning_message is not None:
|
||||||
|
message += "\n"
|
||||||
|
message += licenses_low_warning_message
|
||||||
|
|
||||||
|
send_message_to_signup_notification_stream(sender, user_profile.realm, message)
|
||||||
|
|
||||||
|
# We also send a notification to the Zulip administrative realm
|
||||||
|
admin_realm = get_realm(settings.SYSTEM_BOT_REALM)
|
||||||
|
admin_realm_sender = get_system_bot(sender_email, admin_realm.id)
|
||||||
|
try:
|
||||||
|
# Check whether the stream exists
|
||||||
|
signups_stream = get_signups_stream(admin_realm)
|
||||||
|
# We intentionally use the same strings as above to avoid translation burden.
|
||||||
|
message = _("{user} just signed up for Zulip. (total: {user_count})").format(
|
||||||
|
user=f"{user_profile.full_name} <`{user_profile.email}`>", user_count=user_count
|
||||||
|
)
|
||||||
|
internal_send_stream_message(
|
||||||
|
admin_realm_sender, signups_stream, user_profile.realm.display_subdomain, message
|
||||||
|
)
|
||||||
|
|
||||||
|
except Stream.DoesNotExist:
|
||||||
|
# If the signups stream hasn't been created in the admin
|
||||||
|
# realm, don't auto-create it to send to it; just do nothing.
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def add_new_user_history(user_profile: UserProfile, streams: Iterable[Stream]) -> None:
|
||||||
|
"""Give you the last ONBOARDING_TOTAL_MESSAGES messages on your public
|
||||||
|
streams, so you have something to look at in your home view once
|
||||||
|
you finish the tutorial. The most recent ONBOARDING_UNREAD_MESSAGES
|
||||||
|
are marked unread.
|
||||||
|
"""
|
||||||
|
one_week_ago = timezone_now() - ONBOARDING_RECENT_TIMEDELTA
|
||||||
|
|
||||||
|
recipient_ids = [stream.recipient_id for stream in streams if not stream.invite_only]
|
||||||
|
recent_messages = Message.objects.filter(
|
||||||
|
recipient_id__in=recipient_ids, date_sent__gt=one_week_ago
|
||||||
|
).order_by("-id")
|
||||||
|
message_ids_to_use = list(
|
||||||
|
reversed(recent_messages.values_list("id", flat=True)[0:ONBOARDING_TOTAL_MESSAGES])
|
||||||
|
)
|
||||||
|
if len(message_ids_to_use) == 0:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Handle the race condition where a message arrives between
|
||||||
|
# bulk_add_subscriptions above and the Message query just above
|
||||||
|
already_ids = set(
|
||||||
|
UserMessage.objects.filter(
|
||||||
|
message_id__in=message_ids_to_use, user_profile=user_profile
|
||||||
|
).values_list("message_id", flat=True)
|
||||||
|
)
|
||||||
|
|
||||||
|
# Mark the newest ONBOARDING_UNREAD_MESSAGES as unread.
|
||||||
|
marked_unread = 0
|
||||||
|
ums_to_create = []
|
||||||
|
for message_id in reversed(message_ids_to_use):
|
||||||
|
if message_id in already_ids:
|
||||||
|
continue
|
||||||
|
|
||||||
|
um = UserMessage(user_profile=user_profile, message_id=message_id)
|
||||||
|
if marked_unread < ONBOARDING_UNREAD_MESSAGES:
|
||||||
|
marked_unread += 1
|
||||||
|
else:
|
||||||
|
um.flags = UserMessage.flags.read
|
||||||
|
ums_to_create.append(um)
|
||||||
|
|
||||||
|
UserMessage.objects.bulk_create(reversed(ums_to_create))
|
||||||
|
|
||||||
|
|
||||||
|
# Does the processing for a new user account:
|
||||||
|
# * Subscribes to default/invitation streams
|
||||||
|
# * Fills in some recent historical messages
|
||||||
|
# * Notifies other users in realm and Zulip about the signup
|
||||||
|
# * Deactivates PreregistrationUser objects
|
||||||
|
def process_new_human_user(
|
||||||
|
user_profile: UserProfile,
|
||||||
|
prereg_user: Optional[PreregistrationUser] = None,
|
||||||
|
default_stream_groups: Sequence[DefaultStreamGroup] = [],
|
||||||
|
realm_creation: bool = False,
|
||||||
|
) -> None:
|
||||||
|
realm = user_profile.realm
|
||||||
|
|
||||||
|
mit_beta_user = realm.is_zephyr_mirror_realm
|
||||||
|
if prereg_user is not None:
|
||||||
|
streams: List[Stream] = list(prereg_user.streams.all())
|
||||||
|
acting_user: Optional[UserProfile] = prereg_user.referred_by
|
||||||
|
|
||||||
|
# A PregistrationUser should not be used for another UserProfile
|
||||||
|
assert prereg_user.created_user is None, "PregistrationUser should not be reused"
|
||||||
|
else:
|
||||||
|
streams = []
|
||||||
|
acting_user = None
|
||||||
|
|
||||||
|
# If the user's invitation didn't explicitly list some streams, we
|
||||||
|
# add the default streams
|
||||||
|
if len(streams) == 0:
|
||||||
|
streams = get_default_subs(user_profile)
|
||||||
|
|
||||||
|
for default_stream_group in default_stream_groups:
|
||||||
|
default_stream_group_streams = default_stream_group.streams.all()
|
||||||
|
for stream in default_stream_group_streams:
|
||||||
|
if stream not in streams:
|
||||||
|
streams.append(stream)
|
||||||
|
|
||||||
|
bulk_add_subscriptions(
|
||||||
|
realm,
|
||||||
|
streams,
|
||||||
|
[user_profile],
|
||||||
|
from_user_creation=True,
|
||||||
|
acting_user=acting_user,
|
||||||
|
)
|
||||||
|
|
||||||
|
add_new_user_history(user_profile, streams)
|
||||||
|
|
||||||
|
# mit_beta_users don't have a referred_by field
|
||||||
|
if (
|
||||||
|
not mit_beta_user
|
||||||
|
and prereg_user is not None
|
||||||
|
and prereg_user.referred_by is not None
|
||||||
|
and prereg_user.referred_by.is_active
|
||||||
|
):
|
||||||
|
# This is a cross-realm private message.
|
||||||
|
with override_language(prereg_user.referred_by.default_language):
|
||||||
|
internal_send_private_message(
|
||||||
|
get_system_bot(settings.NOTIFICATION_BOT, prereg_user.referred_by.realm_id),
|
||||||
|
prereg_user.referred_by,
|
||||||
|
_("{user} accepted your invitation to join Zulip!").format(
|
||||||
|
user=f"{user_profile.full_name} <`{user_profile.email}`>"
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
# Revoke all preregistration users except prereg_user, and link prereg_user to
|
||||||
|
# the created user
|
||||||
|
if prereg_user is None:
|
||||||
|
assert not realm_creation, "realm_creation should only happen with a PreregistrationUser"
|
||||||
|
|
||||||
|
if prereg_user is not None:
|
||||||
|
prereg_user.status = confirmation_settings.STATUS_ACTIVE
|
||||||
|
prereg_user.created_user = user_profile
|
||||||
|
prereg_user.save(update_fields=["status", "created_user"])
|
||||||
|
|
||||||
|
# In the special case of realm creation, there can be no additional PreregistrationUser
|
||||||
|
# for us to want to modify - because other realm_creation PreregistrationUsers should be
|
||||||
|
# left usable for creating different realms.
|
||||||
|
if not realm_creation:
|
||||||
|
# Mark any other PreregistrationUsers in the realm that are STATUS_ACTIVE as
|
||||||
|
# inactive so we can keep track of the PreregistrationUser we
|
||||||
|
# actually used for analytics.
|
||||||
|
if prereg_user is not None:
|
||||||
|
PreregistrationUser.objects.filter(
|
||||||
|
email__iexact=user_profile.delivery_email, realm=user_profile.realm
|
||||||
|
).exclude(id=prereg_user.id).update(status=confirmation_settings.STATUS_REVOKED)
|
||||||
|
else:
|
||||||
|
PreregistrationUser.objects.filter(
|
||||||
|
email__iexact=user_profile.delivery_email, realm=user_profile.realm
|
||||||
|
).update(status=confirmation_settings.STATUS_REVOKED)
|
||||||
|
|
||||||
|
if prereg_user is not None and prereg_user.referred_by is not None:
|
||||||
|
notify_invites_changed(user_profile.realm)
|
||||||
|
|
||||||
|
notify_new_user(user_profile)
|
||||||
|
# Clear any scheduled invitation emails to prevent them
|
||||||
|
# from being sent after the user is created.
|
||||||
|
clear_scheduled_invitation_emails(user_profile.delivery_email)
|
||||||
|
if realm.send_welcome_emails:
|
||||||
|
enqueue_welcome_emails(user_profile, realm_creation)
|
||||||
|
|
||||||
|
# We have an import loop here; it's intentional, because we want
|
||||||
|
# to keep all the onboarding code in zerver/lib/onboarding.py.
|
||||||
|
from zerver.lib.onboarding import send_initial_pms
|
||||||
|
|
||||||
|
send_initial_pms(user_profile)
|
||||||
|
|
||||||
|
|
||||||
|
def notify_created_user(user_profile: UserProfile) -> None:
|
||||||
|
user_row = user_profile_to_user_row(user_profile)
|
||||||
|
person = format_user_row(
|
||||||
|
user_profile.realm,
|
||||||
|
user_profile,
|
||||||
|
user_row,
|
||||||
|
# Since we don't know what the client
|
||||||
|
# supports at this point in the code, we
|
||||||
|
# just assume client_gravatar and
|
||||||
|
# user_avatar_url_field_optional = False :(
|
||||||
|
client_gravatar=False,
|
||||||
|
user_avatar_url_field_optional=False,
|
||||||
|
# We assume there's no custom profile
|
||||||
|
# field data for a new user; initial
|
||||||
|
# values are expected to be added in a
|
||||||
|
# later event.
|
||||||
|
custom_profile_field_data={},
|
||||||
|
)
|
||||||
|
event: Dict[str, Any] = dict(type="realm_user", op="add", person=person)
|
||||||
|
send_event(user_profile.realm, event, active_user_ids(user_profile.realm_id))
|
||||||
|
|
||||||
|
|
||||||
|
def created_bot_event(user_profile: UserProfile) -> Dict[str, Any]:
|
||||||
|
def stream_name(stream: Optional[Stream]) -> Optional[str]:
|
||||||
|
if not stream:
|
||||||
|
return None
|
||||||
|
return stream.name
|
||||||
|
|
||||||
|
default_sending_stream_name = stream_name(user_profile.default_sending_stream)
|
||||||
|
default_events_register_stream_name = stream_name(user_profile.default_events_register_stream)
|
||||||
|
|
||||||
|
bot = dict(
|
||||||
|
email=user_profile.email,
|
||||||
|
user_id=user_profile.id,
|
||||||
|
full_name=user_profile.full_name,
|
||||||
|
bot_type=user_profile.bot_type,
|
||||||
|
is_active=user_profile.is_active,
|
||||||
|
api_key=get_api_key(user_profile),
|
||||||
|
default_sending_stream=default_sending_stream_name,
|
||||||
|
default_events_register_stream=default_events_register_stream_name,
|
||||||
|
default_all_public_streams=user_profile.default_all_public_streams,
|
||||||
|
avatar_url=avatar_url(user_profile),
|
||||||
|
services=get_service_dicts_for_bot(user_profile.id),
|
||||||
|
)
|
||||||
|
|
||||||
|
# Set the owner key only when the bot has an owner.
|
||||||
|
# The default bots don't have an owner. So don't
|
||||||
|
# set the owner key while reactivating them.
|
||||||
|
if user_profile.bot_owner is not None:
|
||||||
|
bot["owner_id"] = user_profile.bot_owner.id
|
||||||
|
|
||||||
|
return dict(type="realm_bot", op="add", bot=bot)
|
||||||
|
|
||||||
|
|
||||||
|
def notify_created_bot(user_profile: UserProfile) -> None:
|
||||||
|
event = created_bot_event(user_profile)
|
||||||
|
send_event(user_profile.realm, event, bot_owner_user_ids(user_profile))
|
||||||
|
|
||||||
|
|
||||||
|
def do_create_user(
|
||||||
|
email: str,
|
||||||
|
password: Optional[str],
|
||||||
|
realm: Realm,
|
||||||
|
full_name: str,
|
||||||
|
bot_type: Optional[int] = None,
|
||||||
|
role: Optional[int] = None,
|
||||||
|
bot_owner: Optional[UserProfile] = None,
|
||||||
|
tos_version: Optional[str] = None,
|
||||||
|
timezone: str = "",
|
||||||
|
avatar_source: str = UserProfile.AVATAR_FROM_GRAVATAR,
|
||||||
|
default_sending_stream: Optional[Stream] = None,
|
||||||
|
default_events_register_stream: Optional[Stream] = None,
|
||||||
|
default_all_public_streams: Optional[bool] = None,
|
||||||
|
prereg_user: Optional[PreregistrationUser] = None,
|
||||||
|
default_stream_groups: Sequence[DefaultStreamGroup] = [],
|
||||||
|
source_profile: Optional[UserProfile] = None,
|
||||||
|
realm_creation: bool = False,
|
||||||
|
*,
|
||||||
|
acting_user: Optional[UserProfile],
|
||||||
|
enable_marketing_emails: bool = True,
|
||||||
|
) -> UserProfile:
|
||||||
|
with transaction.atomic():
|
||||||
|
user_profile = create_user(
|
||||||
|
email=email,
|
||||||
|
password=password,
|
||||||
|
realm=realm,
|
||||||
|
full_name=full_name,
|
||||||
|
role=role,
|
||||||
|
bot_type=bot_type,
|
||||||
|
bot_owner=bot_owner,
|
||||||
|
tos_version=tos_version,
|
||||||
|
timezone=timezone,
|
||||||
|
avatar_source=avatar_source,
|
||||||
|
default_sending_stream=default_sending_stream,
|
||||||
|
default_events_register_stream=default_events_register_stream,
|
||||||
|
default_all_public_streams=default_all_public_streams,
|
||||||
|
source_profile=source_profile,
|
||||||
|
enable_marketing_emails=enable_marketing_emails,
|
||||||
|
)
|
||||||
|
|
||||||
|
event_time = user_profile.date_joined
|
||||||
|
if not acting_user:
|
||||||
|
acting_user = user_profile
|
||||||
|
RealmAuditLog.objects.create(
|
||||||
|
realm=user_profile.realm,
|
||||||
|
acting_user=acting_user,
|
||||||
|
modified_user=user_profile,
|
||||||
|
event_type=RealmAuditLog.USER_CREATED,
|
||||||
|
event_time=event_time,
|
||||||
|
extra_data=orjson.dumps(
|
||||||
|
{
|
||||||
|
RealmAuditLog.ROLE_COUNT: realm_user_count_by_role(user_profile.realm),
|
||||||
|
}
|
||||||
|
).decode(),
|
||||||
|
)
|
||||||
|
|
||||||
|
if realm_creation:
|
||||||
|
# If this user just created a realm, make sure they are
|
||||||
|
# properly tagged as the creator of the realm.
|
||||||
|
realm_creation_audit_log = (
|
||||||
|
RealmAuditLog.objects.filter(event_type=RealmAuditLog.REALM_CREATED, realm=realm)
|
||||||
|
.order_by("id")
|
||||||
|
.last()
|
||||||
|
)
|
||||||
|
assert realm_creation_audit_log is not None
|
||||||
|
realm_creation_audit_log.acting_user = user_profile
|
||||||
|
realm_creation_audit_log.save(update_fields=["acting_user"])
|
||||||
|
|
||||||
|
do_increment_logging_stat(
|
||||||
|
user_profile.realm,
|
||||||
|
COUNT_STATS["active_users_log:is_bot:day"],
|
||||||
|
user_profile.is_bot,
|
||||||
|
event_time,
|
||||||
|
)
|
||||||
|
if settings.BILLING_ENABLED:
|
||||||
|
update_license_ledger_if_needed(user_profile.realm, event_time)
|
||||||
|
|
||||||
|
system_user_group = get_system_user_group_for_user(user_profile)
|
||||||
|
UserGroupMembership.objects.create(user_profile=user_profile, user_group=system_user_group)
|
||||||
|
|
||||||
|
if user_profile.role == UserProfile.ROLE_MEMBER and not user_profile.is_provisional_member:
|
||||||
|
full_members_system_group = UserGroup.objects.get(
|
||||||
|
name="@role:fullmembers", realm=user_profile.realm, is_system_group=True
|
||||||
|
)
|
||||||
|
UserGroupMembership.objects.create(
|
||||||
|
user_profile=user_profile, user_group=full_members_system_group
|
||||||
|
)
|
||||||
|
|
||||||
|
# Note that for bots, the caller will send an additional event
|
||||||
|
# with bot-specific info like services.
|
||||||
|
notify_created_user(user_profile)
|
||||||
|
|
||||||
|
do_send_user_group_members_update_event("add_members", system_user_group, [user_profile.id])
|
||||||
|
if user_profile.role == UserProfile.ROLE_MEMBER and not user_profile.is_provisional_member:
|
||||||
|
do_send_user_group_members_update_event(
|
||||||
|
"add_members", full_members_system_group, [user_profile.id]
|
||||||
|
)
|
||||||
|
|
||||||
|
if bot_type is None:
|
||||||
|
process_new_human_user(
|
||||||
|
user_profile,
|
||||||
|
prereg_user=prereg_user,
|
||||||
|
default_stream_groups=default_stream_groups,
|
||||||
|
realm_creation=realm_creation,
|
||||||
|
)
|
||||||
|
|
||||||
|
if realm_creation:
|
||||||
|
assert realm.signup_notifications_stream is not None
|
||||||
|
bulk_add_subscriptions(
|
||||||
|
realm, [realm.signup_notifications_stream], [user_profile], acting_user=None
|
||||||
|
)
|
||||||
|
|
||||||
|
from zerver.lib.onboarding import send_initial_realm_messages
|
||||||
|
|
||||||
|
send_initial_realm_messages(realm)
|
||||||
|
|
||||||
|
return user_profile
|
||||||
|
|
||||||
|
|
||||||
|
def do_activate_mirror_dummy_user(
|
||||||
|
user_profile: UserProfile, *, acting_user: Optional[UserProfile]
|
||||||
|
) -> None:
|
||||||
|
"""Called to have a user "take over" a "mirror dummy" user
|
||||||
|
(i.e. is_mirror_dummy=True) account when they sign up with the
|
||||||
|
same email address.
|
||||||
|
|
||||||
|
Essentially, the result should be as though we had created the
|
||||||
|
UserProfile just now with do_create_user, except that the mirror
|
||||||
|
dummy user may appear as the recipient or sender of messages from
|
||||||
|
before their account was fully created.
|
||||||
|
|
||||||
|
TODO: This function likely has bugs resulting from this being a
|
||||||
|
parallel code path to do_create_user; e.g. it likely does not
|
||||||
|
handle preferences or default streams properly.
|
||||||
|
"""
|
||||||
|
with transaction.atomic():
|
||||||
|
change_user_is_active(user_profile, True)
|
||||||
|
user_profile.is_mirror_dummy = False
|
||||||
|
user_profile.set_unusable_password()
|
||||||
|
user_profile.date_joined = timezone_now()
|
||||||
|
user_profile.tos_version = settings.TERMS_OF_SERVICE_VERSION
|
||||||
|
user_profile.save(
|
||||||
|
update_fields=["date_joined", "password", "is_mirror_dummy", "tos_version"]
|
||||||
|
)
|
||||||
|
|
||||||
|
event_time = user_profile.date_joined
|
||||||
|
RealmAuditLog.objects.create(
|
||||||
|
realm=user_profile.realm,
|
||||||
|
modified_user=user_profile,
|
||||||
|
acting_user=acting_user,
|
||||||
|
event_type=RealmAuditLog.USER_ACTIVATED,
|
||||||
|
event_time=event_time,
|
||||||
|
extra_data=orjson.dumps(
|
||||||
|
{
|
||||||
|
RealmAuditLog.ROLE_COUNT: realm_user_count_by_role(user_profile.realm),
|
||||||
|
}
|
||||||
|
).decode(),
|
||||||
|
)
|
||||||
|
do_increment_logging_stat(
|
||||||
|
user_profile.realm,
|
||||||
|
COUNT_STATS["active_users_log:is_bot:day"],
|
||||||
|
user_profile.is_bot,
|
||||||
|
event_time,
|
||||||
|
)
|
||||||
|
if settings.BILLING_ENABLED:
|
||||||
|
update_license_ledger_if_needed(user_profile.realm, event_time)
|
||||||
|
|
||||||
|
notify_created_user(user_profile)
|
||||||
|
|
||||||
|
|
||||||
|
def do_reactivate_user(user_profile: UserProfile, *, acting_user: Optional[UserProfile]) -> None:
|
||||||
|
"""Reactivate a user that had previously been deactivated"""
|
||||||
|
with transaction.atomic():
|
||||||
|
change_user_is_active(user_profile, True)
|
||||||
|
|
||||||
|
event_time = timezone_now()
|
||||||
|
RealmAuditLog.objects.create(
|
||||||
|
realm=user_profile.realm,
|
||||||
|
modified_user=user_profile,
|
||||||
|
acting_user=acting_user,
|
||||||
|
event_type=RealmAuditLog.USER_REACTIVATED,
|
||||||
|
event_time=event_time,
|
||||||
|
extra_data=orjson.dumps(
|
||||||
|
{
|
||||||
|
RealmAuditLog.ROLE_COUNT: realm_user_count_by_role(user_profile.realm),
|
||||||
|
}
|
||||||
|
).decode(),
|
||||||
|
)
|
||||||
|
do_increment_logging_stat(
|
||||||
|
user_profile.realm,
|
||||||
|
COUNT_STATS["active_users_log:is_bot:day"],
|
||||||
|
user_profile.is_bot,
|
||||||
|
event_time,
|
||||||
|
)
|
||||||
|
if settings.BILLING_ENABLED:
|
||||||
|
update_license_ledger_if_needed(user_profile.realm, event_time)
|
||||||
|
|
||||||
|
notify_created_user(user_profile)
|
||||||
|
|
||||||
|
if user_profile.is_bot:
|
||||||
|
notify_created_bot(user_profile)
|
||||||
|
|
||||||
|
subscribed_recipient_ids = Subscription.objects.filter(
|
||||||
|
user_profile_id=user_profile.id, active=True, recipient__type=Recipient.STREAM
|
||||||
|
).values_list("recipient__type_id", flat=True)
|
||||||
|
subscribed_streams = Stream.objects.filter(id__in=subscribed_recipient_ids, deactivated=False)
|
||||||
|
subscriber_peer_info = bulk_get_subscriber_peer_info(
|
||||||
|
realm=user_profile.realm,
|
||||||
|
streams=subscribed_streams,
|
||||||
|
)
|
||||||
|
|
||||||
|
altered_user_dict: Dict[int, Set[int]] = defaultdict(set)
|
||||||
|
for stream in subscribed_streams:
|
||||||
|
altered_user_dict[stream.id] = {user_profile.id}
|
||||||
|
|
||||||
|
stream_dict = {stream.id: stream for stream in subscribed_streams}
|
||||||
|
|
||||||
|
send_peer_subscriber_events(
|
||||||
|
op="peer_add",
|
||||||
|
realm=user_profile.realm,
|
||||||
|
altered_user_dict=altered_user_dict,
|
||||||
|
stream_dict=stream_dict,
|
||||||
|
private_peer_dict=subscriber_peer_info.private_peer_dict,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def get_default_subs(user_profile: UserProfile) -> List[Stream]:
|
||||||
|
# Right now default streams are realm-wide. This wrapper gives us flexibility
|
||||||
|
# to some day further customize how we set up default streams for new users.
|
||||||
|
return get_default_streams_for_realm(user_profile.realm_id)
|
|
@ -16,33 +16,23 @@ from django.utils.translation import override as override_language
|
||||||
from typing_extensions import TypedDict
|
from typing_extensions import TypedDict
|
||||||
|
|
||||||
from analytics.lib.counts import COUNT_STATS, do_increment_logging_stat
|
from analytics.lib.counts import COUNT_STATS, do_increment_logging_stat
|
||||||
from confirmation import settings as confirmation_settings
|
|
||||||
from confirmation.models import Confirmation, create_confirmation_link, generate_key
|
from confirmation.models import Confirmation, create_confirmation_link, generate_key
|
||||||
|
from zerver.actions.create_user import create_historical_user_messages, created_bot_event
|
||||||
from zerver.actions.custom_profile_fields import do_remove_realm_custom_profile_fields
|
from zerver.actions.custom_profile_fields import do_remove_realm_custom_profile_fields
|
||||||
from zerver.actions.default_streams import get_default_streams_for_realm
|
|
||||||
from zerver.actions.invites import notify_invites_changed
|
|
||||||
from zerver.actions.message_send import (
|
from zerver.actions.message_send import (
|
||||||
filter_presence_idle_user_ids,
|
filter_presence_idle_user_ids,
|
||||||
get_recipient_info,
|
get_recipient_info,
|
||||||
internal_send_private_message,
|
|
||||||
internal_send_stream_message,
|
internal_send_stream_message,
|
||||||
render_incoming_message,
|
render_incoming_message,
|
||||||
)
|
)
|
||||||
from zerver.actions.streams import bulk_add_subscriptions, send_peer_subscriber_events
|
|
||||||
from zerver.actions.uploads import check_attachment_reference_change
|
from zerver.actions.uploads import check_attachment_reference_change
|
||||||
from zerver.actions.user_groups import (
|
from zerver.actions.user_groups import update_users_in_full_members_system_group
|
||||||
do_send_user_group_members_update_event,
|
|
||||||
update_users_in_full_members_system_group,
|
|
||||||
)
|
|
||||||
from zerver.actions.user_settings import do_delete_avatar_image, send_user_email_update_event
|
from zerver.actions.user_settings import do_delete_avatar_image, send_user_email_update_event
|
||||||
from zerver.actions.user_topics import do_mute_topic, do_unmute_topic
|
from zerver.actions.user_topics import do_mute_topic, do_unmute_topic
|
||||||
from zerver.actions.users import change_user_is_active, get_service_dicts_for_bot
|
|
||||||
from zerver.lib import retention as retention
|
from zerver.lib import retention as retention
|
||||||
from zerver.lib.avatar import avatar_url
|
|
||||||
from zerver.lib.bulk_create import create_users
|
from zerver.lib.bulk_create import create_users
|
||||||
from zerver.lib.cache import flush_user_profile
|
from zerver.lib.cache import flush_user_profile
|
||||||
from zerver.lib.create_user import create_user, get_display_email_address
|
from zerver.lib.create_user import get_display_email_address
|
||||||
from zerver.lib.email_notifications import enqueue_welcome_emails
|
|
||||||
from zerver.lib.email_validation import email_reserved_for_system_bots_error
|
from zerver.lib.email_validation import email_reserved_for_system_bots_error
|
||||||
from zerver.lib.emoji import check_emoji_request, emoji_name_to_emoji_code
|
from zerver.lib.emoji import check_emoji_request, emoji_name_to_emoji_code
|
||||||
from zerver.lib.exceptions import JsonableError
|
from zerver.lib.exceptions import JsonableError
|
||||||
|
@ -62,15 +52,10 @@ from zerver.lib.message import (
|
||||||
)
|
)
|
||||||
from zerver.lib.queue import queue_json_publish
|
from zerver.lib.queue import queue_json_publish
|
||||||
from zerver.lib.retention import move_messages_to_archive
|
from zerver.lib.retention import move_messages_to_archive
|
||||||
from zerver.lib.send_email import (
|
from zerver.lib.send_email import FromAddress, send_email_to_admins
|
||||||
FromAddress,
|
|
||||||
clear_scheduled_invitation_emails,
|
|
||||||
send_email_to_admins,
|
|
||||||
)
|
|
||||||
from zerver.lib.server_initialization import create_internal_realm, server_initialized
|
from zerver.lib.server_initialization import create_internal_realm, server_initialized
|
||||||
from zerver.lib.sessions import delete_user_sessions
|
from zerver.lib.sessions import delete_user_sessions
|
||||||
from zerver.lib.stream_subscription import (
|
from zerver.lib.stream_subscription import (
|
||||||
bulk_get_subscriber_peer_info,
|
|
||||||
get_active_subscriptions_for_stream_id,
|
get_active_subscriptions_for_stream_id,
|
||||||
subscriber_ids_with_stream_history_access,
|
subscriber_ids_with_stream_history_access,
|
||||||
)
|
)
|
||||||
|
@ -95,25 +80,19 @@ from zerver.lib.topic import (
|
||||||
update_messages_for_topic_edit,
|
update_messages_for_topic_edit,
|
||||||
)
|
)
|
||||||
from zerver.lib.types import EditHistoryEvent
|
from zerver.lib.types import EditHistoryEvent
|
||||||
from zerver.lib.user_counts import realm_user_count, realm_user_count_by_role
|
from zerver.lib.user_counts import realm_user_count_by_role
|
||||||
from zerver.lib.user_groups import (
|
from zerver.lib.user_groups import create_system_user_groups_for_realm
|
||||||
create_system_user_groups_for_realm,
|
|
||||||
get_system_user_group_for_user,
|
|
||||||
)
|
|
||||||
from zerver.lib.user_message import UserMessageLite, bulk_insert_ums
|
from zerver.lib.user_message import UserMessageLite, bulk_insert_ums
|
||||||
from zerver.lib.user_mutes import add_user_mute, get_user_mutes
|
from zerver.lib.user_mutes import add_user_mute, get_user_mutes
|
||||||
from zerver.lib.user_topics import get_users_muting_topic, remove_topic_mute
|
from zerver.lib.user_topics import get_users_muting_topic, remove_topic_mute
|
||||||
from zerver.lib.users import format_user_row, get_api_key, user_profile_to_user_row
|
|
||||||
from zerver.lib.utils import log_statsd_event
|
from zerver.lib.utils import log_statsd_event
|
||||||
from zerver.lib.widget import is_widget_message
|
from zerver.lib.widget import is_widget_message
|
||||||
from zerver.models import (
|
from zerver.models import (
|
||||||
ArchivedAttachment,
|
ArchivedAttachment,
|
||||||
Attachment,
|
Attachment,
|
||||||
DefaultStream,
|
DefaultStream,
|
||||||
DefaultStreamGroup,
|
|
||||||
Message,
|
Message,
|
||||||
MutedUser,
|
MutedUser,
|
||||||
PreregistrationUser,
|
|
||||||
Reaction,
|
Reaction,
|
||||||
Realm,
|
Realm,
|
||||||
RealmAuditLog,
|
RealmAuditLog,
|
||||||
|
@ -122,9 +101,6 @@ from zerver.models import (
|
||||||
Recipient,
|
Recipient,
|
||||||
ScheduledEmail,
|
ScheduledEmail,
|
||||||
Stream,
|
Stream,
|
||||||
Subscription,
|
|
||||||
UserGroup,
|
|
||||||
UserGroupMembership,
|
|
||||||
UserMessage,
|
UserMessage,
|
||||||
UserProfile,
|
UserProfile,
|
||||||
active_user_ids,
|
active_user_ids,
|
||||||
|
@ -138,525 +114,13 @@ from zerver.models import (
|
||||||
from zerver.tornado.django_api import send_event
|
from zerver.tornado.django_api import send_event
|
||||||
|
|
||||||
if settings.BILLING_ENABLED:
|
if settings.BILLING_ENABLED:
|
||||||
from corporate.lib.stripe import (
|
from corporate.lib.stripe import downgrade_now_without_creating_additional_invoices
|
||||||
downgrade_now_without_creating_additional_invoices,
|
|
||||||
update_license_ledger_if_needed,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
ONBOARDING_TOTAL_MESSAGES = 1000
|
|
||||||
ONBOARDING_UNREAD_MESSAGES = 20
|
|
||||||
ONBOARDING_RECENT_TIMEDELTA = datetime.timedelta(weeks=1)
|
|
||||||
|
|
||||||
|
|
||||||
def create_historical_user_messages(*, user_id: int, message_ids: List[int]) -> None:
|
|
||||||
# Users can see and interact with messages sent to streams with
|
|
||||||
# public history for which they do not have a UserMessage because
|
|
||||||
# they were not a subscriber at the time the message was sent.
|
|
||||||
# In order to add emoji reactions or mutate message flags for
|
|
||||||
# those messages, we create UserMessage objects for those messages;
|
|
||||||
# these have the special historical flag which keeps track of the
|
|
||||||
# fact that the user did not receive the message at the time it was sent.
|
|
||||||
for message_id in message_ids:
|
|
||||||
UserMessage.objects.create(
|
|
||||||
user_profile_id=user_id,
|
|
||||||
message_id=message_id,
|
|
||||||
flags=UserMessage.flags.historical | UserMessage.flags.read,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def subscriber_info(user_id: int) -> Dict[str, Any]:
|
def subscriber_info(user_id: int) -> Dict[str, Any]:
|
||||||
return {"id": user_id, "flags": ["read"]}
|
return {"id": user_id, "flags": ["read"]}
|
||||||
|
|
||||||
|
|
||||||
def send_message_to_signup_notification_stream(
|
|
||||||
sender: UserProfile, realm: Realm, message: str, topic_name: str = _("signups")
|
|
||||||
) -> None:
|
|
||||||
signup_notifications_stream = realm.get_signup_notifications_stream()
|
|
||||||
if signup_notifications_stream is None:
|
|
||||||
return
|
|
||||||
|
|
||||||
with override_language(realm.default_language):
|
|
||||||
internal_send_stream_message(sender, signup_notifications_stream, topic_name, message)
|
|
||||||
|
|
||||||
|
|
||||||
def notify_new_user(user_profile: UserProfile) -> None:
|
|
||||||
user_count = realm_user_count(user_profile.realm)
|
|
||||||
sender_email = settings.NOTIFICATION_BOT
|
|
||||||
sender = get_system_bot(sender_email, user_profile.realm_id)
|
|
||||||
|
|
||||||
is_first_user = user_count == 1
|
|
||||||
if not is_first_user:
|
|
||||||
message = _("{user} just signed up for Zulip. (total: {user_count})").format(
|
|
||||||
user=silent_mention_syntax_for_user(user_profile), user_count=user_count
|
|
||||||
)
|
|
||||||
|
|
||||||
if settings.BILLING_ENABLED:
|
|
||||||
from corporate.lib.registration import generate_licenses_low_warning_message_if_required
|
|
||||||
|
|
||||||
licenses_low_warning_message = generate_licenses_low_warning_message_if_required(
|
|
||||||
user_profile.realm
|
|
||||||
)
|
|
||||||
if licenses_low_warning_message is not None:
|
|
||||||
message += "\n"
|
|
||||||
message += licenses_low_warning_message
|
|
||||||
|
|
||||||
send_message_to_signup_notification_stream(sender, user_profile.realm, message)
|
|
||||||
|
|
||||||
# We also send a notification to the Zulip administrative realm
|
|
||||||
admin_realm = get_realm(settings.SYSTEM_BOT_REALM)
|
|
||||||
admin_realm_sender = get_system_bot(sender_email, admin_realm.id)
|
|
||||||
try:
|
|
||||||
# Check whether the stream exists
|
|
||||||
signups_stream = get_signups_stream(admin_realm)
|
|
||||||
# We intentionally use the same strings as above to avoid translation burden.
|
|
||||||
message = _("{user} just signed up for Zulip. (total: {user_count})").format(
|
|
||||||
user=f"{user_profile.full_name} <`{user_profile.email}`>", user_count=user_count
|
|
||||||
)
|
|
||||||
internal_send_stream_message(
|
|
||||||
admin_realm_sender, signups_stream, user_profile.realm.display_subdomain, message
|
|
||||||
)
|
|
||||||
|
|
||||||
except Stream.DoesNotExist:
|
|
||||||
# If the signups stream hasn't been created in the admin
|
|
||||||
# realm, don't auto-create it to send to it; just do nothing.
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
def add_new_user_history(user_profile: UserProfile, streams: Iterable[Stream]) -> None:
|
|
||||||
"""Give you the last ONBOARDING_TOTAL_MESSAGES messages on your public
|
|
||||||
streams, so you have something to look at in your home view once
|
|
||||||
you finish the tutorial. The most recent ONBOARDING_UNREAD_MESSAGES
|
|
||||||
are marked unread.
|
|
||||||
"""
|
|
||||||
one_week_ago = timezone_now() - ONBOARDING_RECENT_TIMEDELTA
|
|
||||||
|
|
||||||
recipient_ids = [stream.recipient_id for stream in streams if not stream.invite_only]
|
|
||||||
recent_messages = Message.objects.filter(
|
|
||||||
recipient_id__in=recipient_ids, date_sent__gt=one_week_ago
|
|
||||||
).order_by("-id")
|
|
||||||
message_ids_to_use = list(
|
|
||||||
reversed(recent_messages.values_list("id", flat=True)[0:ONBOARDING_TOTAL_MESSAGES])
|
|
||||||
)
|
|
||||||
if len(message_ids_to_use) == 0:
|
|
||||||
return
|
|
||||||
|
|
||||||
# Handle the race condition where a message arrives between
|
|
||||||
# bulk_add_subscriptions above and the Message query just above
|
|
||||||
already_ids = set(
|
|
||||||
UserMessage.objects.filter(
|
|
||||||
message_id__in=message_ids_to_use, user_profile=user_profile
|
|
||||||
).values_list("message_id", flat=True)
|
|
||||||
)
|
|
||||||
|
|
||||||
# Mark the newest ONBOARDING_UNREAD_MESSAGES as unread.
|
|
||||||
marked_unread = 0
|
|
||||||
ums_to_create = []
|
|
||||||
for message_id in reversed(message_ids_to_use):
|
|
||||||
if message_id in already_ids:
|
|
||||||
continue
|
|
||||||
|
|
||||||
um = UserMessage(user_profile=user_profile, message_id=message_id)
|
|
||||||
if marked_unread < ONBOARDING_UNREAD_MESSAGES:
|
|
||||||
marked_unread += 1
|
|
||||||
else:
|
|
||||||
um.flags = UserMessage.flags.read
|
|
||||||
ums_to_create.append(um)
|
|
||||||
|
|
||||||
UserMessage.objects.bulk_create(reversed(ums_to_create))
|
|
||||||
|
|
||||||
|
|
||||||
# Does the processing for a new user account:
|
|
||||||
# * Subscribes to default/invitation streams
|
|
||||||
# * Fills in some recent historical messages
|
|
||||||
# * Notifies other users in realm and Zulip about the signup
|
|
||||||
# * Deactivates PreregistrationUser objects
|
|
||||||
def process_new_human_user(
|
|
||||||
user_profile: UserProfile,
|
|
||||||
prereg_user: Optional[PreregistrationUser] = None,
|
|
||||||
default_stream_groups: Sequence[DefaultStreamGroup] = [],
|
|
||||||
realm_creation: bool = False,
|
|
||||||
) -> None:
|
|
||||||
realm = user_profile.realm
|
|
||||||
|
|
||||||
mit_beta_user = realm.is_zephyr_mirror_realm
|
|
||||||
if prereg_user is not None:
|
|
||||||
streams: List[Stream] = list(prereg_user.streams.all())
|
|
||||||
acting_user: Optional[UserProfile] = prereg_user.referred_by
|
|
||||||
|
|
||||||
# A PregistrationUser should not be used for another UserProfile
|
|
||||||
assert prereg_user.created_user is None, "PregistrationUser should not be reused"
|
|
||||||
else:
|
|
||||||
streams = []
|
|
||||||
acting_user = None
|
|
||||||
|
|
||||||
# If the user's invitation didn't explicitly list some streams, we
|
|
||||||
# add the default streams
|
|
||||||
if len(streams) == 0:
|
|
||||||
streams = get_default_subs(user_profile)
|
|
||||||
|
|
||||||
for default_stream_group in default_stream_groups:
|
|
||||||
default_stream_group_streams = default_stream_group.streams.all()
|
|
||||||
for stream in default_stream_group_streams:
|
|
||||||
if stream not in streams:
|
|
||||||
streams.append(stream)
|
|
||||||
|
|
||||||
bulk_add_subscriptions(
|
|
||||||
realm,
|
|
||||||
streams,
|
|
||||||
[user_profile],
|
|
||||||
from_user_creation=True,
|
|
||||||
acting_user=acting_user,
|
|
||||||
)
|
|
||||||
|
|
||||||
add_new_user_history(user_profile, streams)
|
|
||||||
|
|
||||||
# mit_beta_users don't have a referred_by field
|
|
||||||
if (
|
|
||||||
not mit_beta_user
|
|
||||||
and prereg_user is not None
|
|
||||||
and prereg_user.referred_by is not None
|
|
||||||
and prereg_user.referred_by.is_active
|
|
||||||
):
|
|
||||||
# This is a cross-realm private message.
|
|
||||||
with override_language(prereg_user.referred_by.default_language):
|
|
||||||
internal_send_private_message(
|
|
||||||
get_system_bot(settings.NOTIFICATION_BOT, prereg_user.referred_by.realm_id),
|
|
||||||
prereg_user.referred_by,
|
|
||||||
_("{user} accepted your invitation to join Zulip!").format(
|
|
||||||
user=f"{user_profile.full_name} <`{user_profile.email}`>"
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
# Revoke all preregistration users except prereg_user, and link prereg_user to
|
|
||||||
# the created user
|
|
||||||
if prereg_user is None:
|
|
||||||
assert not realm_creation, "realm_creation should only happen with a PreregistrationUser"
|
|
||||||
|
|
||||||
if prereg_user is not None:
|
|
||||||
prereg_user.status = confirmation_settings.STATUS_ACTIVE
|
|
||||||
prereg_user.created_user = user_profile
|
|
||||||
prereg_user.save(update_fields=["status", "created_user"])
|
|
||||||
|
|
||||||
# In the special case of realm creation, there can be no additional PreregistrationUser
|
|
||||||
# for us to want to modify - because other realm_creation PreregistrationUsers should be
|
|
||||||
# left usable for creating different realms.
|
|
||||||
if not realm_creation:
|
|
||||||
# Mark any other PreregistrationUsers in the realm that are STATUS_ACTIVE as
|
|
||||||
# inactive so we can keep track of the PreregistrationUser we
|
|
||||||
# actually used for analytics.
|
|
||||||
if prereg_user is not None:
|
|
||||||
PreregistrationUser.objects.filter(
|
|
||||||
email__iexact=user_profile.delivery_email, realm=user_profile.realm
|
|
||||||
).exclude(id=prereg_user.id).update(status=confirmation_settings.STATUS_REVOKED)
|
|
||||||
else:
|
|
||||||
PreregistrationUser.objects.filter(
|
|
||||||
email__iexact=user_profile.delivery_email, realm=user_profile.realm
|
|
||||||
).update(status=confirmation_settings.STATUS_REVOKED)
|
|
||||||
|
|
||||||
if prereg_user is not None and prereg_user.referred_by is not None:
|
|
||||||
notify_invites_changed(user_profile.realm)
|
|
||||||
|
|
||||||
notify_new_user(user_profile)
|
|
||||||
# Clear any scheduled invitation emails to prevent them
|
|
||||||
# from being sent after the user is created.
|
|
||||||
clear_scheduled_invitation_emails(user_profile.delivery_email)
|
|
||||||
if realm.send_welcome_emails:
|
|
||||||
enqueue_welcome_emails(user_profile, realm_creation)
|
|
||||||
|
|
||||||
# We have an import loop here; it's intentional, because we want
|
|
||||||
# to keep all the onboarding code in zerver/lib/onboarding.py.
|
|
||||||
from zerver.lib.onboarding import send_initial_pms
|
|
||||||
|
|
||||||
send_initial_pms(user_profile)
|
|
||||||
|
|
||||||
|
|
||||||
def notify_created_user(user_profile: UserProfile) -> None:
|
|
||||||
user_row = user_profile_to_user_row(user_profile)
|
|
||||||
person = format_user_row(
|
|
||||||
user_profile.realm,
|
|
||||||
user_profile,
|
|
||||||
user_row,
|
|
||||||
# Since we don't know what the client
|
|
||||||
# supports at this point in the code, we
|
|
||||||
# just assume client_gravatar and
|
|
||||||
# user_avatar_url_field_optional = False :(
|
|
||||||
client_gravatar=False,
|
|
||||||
user_avatar_url_field_optional=False,
|
|
||||||
# We assume there's no custom profile
|
|
||||||
# field data for a new user; initial
|
|
||||||
# values are expected to be added in a
|
|
||||||
# later event.
|
|
||||||
custom_profile_field_data={},
|
|
||||||
)
|
|
||||||
event: Dict[str, Any] = dict(type="realm_user", op="add", person=person)
|
|
||||||
send_event(user_profile.realm, event, active_user_ids(user_profile.realm_id))
|
|
||||||
|
|
||||||
|
|
||||||
def created_bot_event(user_profile: UserProfile) -> Dict[str, Any]:
|
|
||||||
def stream_name(stream: Optional[Stream]) -> Optional[str]:
|
|
||||||
if not stream:
|
|
||||||
return None
|
|
||||||
return stream.name
|
|
||||||
|
|
||||||
default_sending_stream_name = stream_name(user_profile.default_sending_stream)
|
|
||||||
default_events_register_stream_name = stream_name(user_profile.default_events_register_stream)
|
|
||||||
|
|
||||||
bot = dict(
|
|
||||||
email=user_profile.email,
|
|
||||||
user_id=user_profile.id,
|
|
||||||
full_name=user_profile.full_name,
|
|
||||||
bot_type=user_profile.bot_type,
|
|
||||||
is_active=user_profile.is_active,
|
|
||||||
api_key=get_api_key(user_profile),
|
|
||||||
default_sending_stream=default_sending_stream_name,
|
|
||||||
default_events_register_stream=default_events_register_stream_name,
|
|
||||||
default_all_public_streams=user_profile.default_all_public_streams,
|
|
||||||
avatar_url=avatar_url(user_profile),
|
|
||||||
services=get_service_dicts_for_bot(user_profile.id),
|
|
||||||
)
|
|
||||||
|
|
||||||
# Set the owner key only when the bot has an owner.
|
|
||||||
# The default bots don't have an owner. So don't
|
|
||||||
# set the owner key while reactivating them.
|
|
||||||
if user_profile.bot_owner is not None:
|
|
||||||
bot["owner_id"] = user_profile.bot_owner.id
|
|
||||||
|
|
||||||
return dict(type="realm_bot", op="add", bot=bot)
|
|
||||||
|
|
||||||
|
|
||||||
def notify_created_bot(user_profile: UserProfile) -> None:
|
|
||||||
event = created_bot_event(user_profile)
|
|
||||||
send_event(user_profile.realm, event, bot_owner_user_ids(user_profile))
|
|
||||||
|
|
||||||
|
|
||||||
def do_create_user(
|
|
||||||
email: str,
|
|
||||||
password: Optional[str],
|
|
||||||
realm: Realm,
|
|
||||||
full_name: str,
|
|
||||||
bot_type: Optional[int] = None,
|
|
||||||
role: Optional[int] = None,
|
|
||||||
bot_owner: Optional[UserProfile] = None,
|
|
||||||
tos_version: Optional[str] = None,
|
|
||||||
timezone: str = "",
|
|
||||||
avatar_source: str = UserProfile.AVATAR_FROM_GRAVATAR,
|
|
||||||
default_sending_stream: Optional[Stream] = None,
|
|
||||||
default_events_register_stream: Optional[Stream] = None,
|
|
||||||
default_all_public_streams: Optional[bool] = None,
|
|
||||||
prereg_user: Optional[PreregistrationUser] = None,
|
|
||||||
default_stream_groups: Sequence[DefaultStreamGroup] = [],
|
|
||||||
source_profile: Optional[UserProfile] = None,
|
|
||||||
realm_creation: bool = False,
|
|
||||||
*,
|
|
||||||
acting_user: Optional[UserProfile],
|
|
||||||
enable_marketing_emails: bool = True,
|
|
||||||
) -> UserProfile:
|
|
||||||
with transaction.atomic():
|
|
||||||
user_profile = create_user(
|
|
||||||
email=email,
|
|
||||||
password=password,
|
|
||||||
realm=realm,
|
|
||||||
full_name=full_name,
|
|
||||||
role=role,
|
|
||||||
bot_type=bot_type,
|
|
||||||
bot_owner=bot_owner,
|
|
||||||
tos_version=tos_version,
|
|
||||||
timezone=timezone,
|
|
||||||
avatar_source=avatar_source,
|
|
||||||
default_sending_stream=default_sending_stream,
|
|
||||||
default_events_register_stream=default_events_register_stream,
|
|
||||||
default_all_public_streams=default_all_public_streams,
|
|
||||||
source_profile=source_profile,
|
|
||||||
enable_marketing_emails=enable_marketing_emails,
|
|
||||||
)
|
|
||||||
|
|
||||||
event_time = user_profile.date_joined
|
|
||||||
if not acting_user:
|
|
||||||
acting_user = user_profile
|
|
||||||
RealmAuditLog.objects.create(
|
|
||||||
realm=user_profile.realm,
|
|
||||||
acting_user=acting_user,
|
|
||||||
modified_user=user_profile,
|
|
||||||
event_type=RealmAuditLog.USER_CREATED,
|
|
||||||
event_time=event_time,
|
|
||||||
extra_data=orjson.dumps(
|
|
||||||
{
|
|
||||||
RealmAuditLog.ROLE_COUNT: realm_user_count_by_role(user_profile.realm),
|
|
||||||
}
|
|
||||||
).decode(),
|
|
||||||
)
|
|
||||||
|
|
||||||
if realm_creation:
|
|
||||||
# If this user just created a realm, make sure they are
|
|
||||||
# properly tagged as the creator of the realm.
|
|
||||||
realm_creation_audit_log = (
|
|
||||||
RealmAuditLog.objects.filter(event_type=RealmAuditLog.REALM_CREATED, realm=realm)
|
|
||||||
.order_by("id")
|
|
||||||
.last()
|
|
||||||
)
|
|
||||||
assert realm_creation_audit_log is not None
|
|
||||||
realm_creation_audit_log.acting_user = user_profile
|
|
||||||
realm_creation_audit_log.save(update_fields=["acting_user"])
|
|
||||||
|
|
||||||
do_increment_logging_stat(
|
|
||||||
user_profile.realm,
|
|
||||||
COUNT_STATS["active_users_log:is_bot:day"],
|
|
||||||
user_profile.is_bot,
|
|
||||||
event_time,
|
|
||||||
)
|
|
||||||
if settings.BILLING_ENABLED:
|
|
||||||
update_license_ledger_if_needed(user_profile.realm, event_time)
|
|
||||||
|
|
||||||
system_user_group = get_system_user_group_for_user(user_profile)
|
|
||||||
UserGroupMembership.objects.create(user_profile=user_profile, user_group=system_user_group)
|
|
||||||
|
|
||||||
if user_profile.role == UserProfile.ROLE_MEMBER and not user_profile.is_provisional_member:
|
|
||||||
full_members_system_group = UserGroup.objects.get(
|
|
||||||
name="@role:fullmembers", realm=user_profile.realm, is_system_group=True
|
|
||||||
)
|
|
||||||
UserGroupMembership.objects.create(
|
|
||||||
user_profile=user_profile, user_group=full_members_system_group
|
|
||||||
)
|
|
||||||
|
|
||||||
# Note that for bots, the caller will send an additional event
|
|
||||||
# with bot-specific info like services.
|
|
||||||
notify_created_user(user_profile)
|
|
||||||
|
|
||||||
do_send_user_group_members_update_event("add_members", system_user_group, [user_profile.id])
|
|
||||||
if user_profile.role == UserProfile.ROLE_MEMBER and not user_profile.is_provisional_member:
|
|
||||||
do_send_user_group_members_update_event(
|
|
||||||
"add_members", full_members_system_group, [user_profile.id]
|
|
||||||
)
|
|
||||||
|
|
||||||
if bot_type is None:
|
|
||||||
process_new_human_user(
|
|
||||||
user_profile,
|
|
||||||
prereg_user=prereg_user,
|
|
||||||
default_stream_groups=default_stream_groups,
|
|
||||||
realm_creation=realm_creation,
|
|
||||||
)
|
|
||||||
|
|
||||||
if realm_creation:
|
|
||||||
assert realm.signup_notifications_stream is not None
|
|
||||||
bulk_add_subscriptions(
|
|
||||||
realm, [realm.signup_notifications_stream], [user_profile], acting_user=None
|
|
||||||
)
|
|
||||||
|
|
||||||
from zerver.lib.onboarding import send_initial_realm_messages
|
|
||||||
|
|
||||||
send_initial_realm_messages(realm)
|
|
||||||
|
|
||||||
return user_profile
|
|
||||||
|
|
||||||
|
|
||||||
def do_activate_mirror_dummy_user(
|
|
||||||
user_profile: UserProfile, *, acting_user: Optional[UserProfile]
|
|
||||||
) -> None:
|
|
||||||
"""Called to have a user "take over" a "mirror dummy" user
|
|
||||||
(i.e. is_mirror_dummy=True) account when they sign up with the
|
|
||||||
same email address.
|
|
||||||
|
|
||||||
Essentially, the result should be as though we had created the
|
|
||||||
UserProfile just now with do_create_user, except that the mirror
|
|
||||||
dummy user may appear as the recipient or sender of messages from
|
|
||||||
before their account was fully created.
|
|
||||||
|
|
||||||
TODO: This function likely has bugs resulting from this being a
|
|
||||||
parallel code path to do_create_user; e.g. it likely does not
|
|
||||||
handle preferences or default streams properly.
|
|
||||||
"""
|
|
||||||
with transaction.atomic():
|
|
||||||
change_user_is_active(user_profile, True)
|
|
||||||
user_profile.is_mirror_dummy = False
|
|
||||||
user_profile.set_unusable_password()
|
|
||||||
user_profile.date_joined = timezone_now()
|
|
||||||
user_profile.tos_version = settings.TERMS_OF_SERVICE_VERSION
|
|
||||||
user_profile.save(
|
|
||||||
update_fields=["date_joined", "password", "is_mirror_dummy", "tos_version"]
|
|
||||||
)
|
|
||||||
|
|
||||||
event_time = user_profile.date_joined
|
|
||||||
RealmAuditLog.objects.create(
|
|
||||||
realm=user_profile.realm,
|
|
||||||
modified_user=user_profile,
|
|
||||||
acting_user=acting_user,
|
|
||||||
event_type=RealmAuditLog.USER_ACTIVATED,
|
|
||||||
event_time=event_time,
|
|
||||||
extra_data=orjson.dumps(
|
|
||||||
{
|
|
||||||
RealmAuditLog.ROLE_COUNT: realm_user_count_by_role(user_profile.realm),
|
|
||||||
}
|
|
||||||
).decode(),
|
|
||||||
)
|
|
||||||
do_increment_logging_stat(
|
|
||||||
user_profile.realm,
|
|
||||||
COUNT_STATS["active_users_log:is_bot:day"],
|
|
||||||
user_profile.is_bot,
|
|
||||||
event_time,
|
|
||||||
)
|
|
||||||
if settings.BILLING_ENABLED:
|
|
||||||
update_license_ledger_if_needed(user_profile.realm, event_time)
|
|
||||||
|
|
||||||
notify_created_user(user_profile)
|
|
||||||
|
|
||||||
|
|
||||||
def do_reactivate_user(user_profile: UserProfile, *, acting_user: Optional[UserProfile]) -> None:
|
|
||||||
"""Reactivate a user that had previously been deactivated"""
|
|
||||||
with transaction.atomic():
|
|
||||||
change_user_is_active(user_profile, True)
|
|
||||||
|
|
||||||
event_time = timezone_now()
|
|
||||||
RealmAuditLog.objects.create(
|
|
||||||
realm=user_profile.realm,
|
|
||||||
modified_user=user_profile,
|
|
||||||
acting_user=acting_user,
|
|
||||||
event_type=RealmAuditLog.USER_REACTIVATED,
|
|
||||||
event_time=event_time,
|
|
||||||
extra_data=orjson.dumps(
|
|
||||||
{
|
|
||||||
RealmAuditLog.ROLE_COUNT: realm_user_count_by_role(user_profile.realm),
|
|
||||||
}
|
|
||||||
).decode(),
|
|
||||||
)
|
|
||||||
do_increment_logging_stat(
|
|
||||||
user_profile.realm,
|
|
||||||
COUNT_STATS["active_users_log:is_bot:day"],
|
|
||||||
user_profile.is_bot,
|
|
||||||
event_time,
|
|
||||||
)
|
|
||||||
if settings.BILLING_ENABLED:
|
|
||||||
update_license_ledger_if_needed(user_profile.realm, event_time)
|
|
||||||
|
|
||||||
notify_created_user(user_profile)
|
|
||||||
|
|
||||||
if user_profile.is_bot:
|
|
||||||
notify_created_bot(user_profile)
|
|
||||||
|
|
||||||
subscribed_recipient_ids = Subscription.objects.filter(
|
|
||||||
user_profile_id=user_profile.id, active=True, recipient__type=Recipient.STREAM
|
|
||||||
).values_list("recipient__type_id", flat=True)
|
|
||||||
subscribed_streams = Stream.objects.filter(id__in=subscribed_recipient_ids, deactivated=False)
|
|
||||||
subscriber_peer_info = bulk_get_subscriber_peer_info(
|
|
||||||
realm=user_profile.realm,
|
|
||||||
streams=subscribed_streams,
|
|
||||||
)
|
|
||||||
|
|
||||||
altered_user_dict: Dict[int, Set[int]] = defaultdict(set)
|
|
||||||
for stream in subscribed_streams:
|
|
||||||
altered_user_dict[stream.id] = {user_profile.id}
|
|
||||||
|
|
||||||
stream_dict = {stream.id: stream for stream in subscribed_streams}
|
|
||||||
|
|
||||||
send_peer_subscriber_events(
|
|
||||||
op="peer_add",
|
|
||||||
realm=user_profile.realm,
|
|
||||||
altered_user_dict=altered_user_dict,
|
|
||||||
stream_dict=stream_dict,
|
|
||||||
private_peer_dict=subscriber_peer_info.private_peer_dict,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def active_humans_in_realm(realm: Realm) -> Sequence[UserProfile]:
|
def active_humans_in_realm(realm: Realm) -> Sequence[UserProfile]:
|
||||||
return UserProfile.objects.filter(realm=realm, is_active=True, is_bot=False)
|
return UserProfile.objects.filter(realm=realm, is_active=True, is_bot=False)
|
||||||
|
|
||||||
|
@ -1870,12 +1334,6 @@ def do_create_realm(
|
||||||
return realm
|
return realm
|
||||||
|
|
||||||
|
|
||||||
def get_default_subs(user_profile: UserProfile) -> List[Stream]:
|
|
||||||
# Right now default streams are realm-wide. This wrapper gives us flexibility
|
|
||||||
# to some day further customize how we set up default streams for new users.
|
|
||||||
return get_default_streams_for_realm(user_profile.realm_id)
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class ReadMessagesEvent:
|
class ReadMessagesEvent:
|
||||||
messages: List[int]
|
messages: List[int]
|
||||||
|
|
|
@ -9,9 +9,9 @@ from django.http import HttpRequest
|
||||||
from django_scim.adapters import SCIMUser
|
from django_scim.adapters import SCIMUser
|
||||||
from scim2_filter_parser.attr_paths import AttrPath
|
from scim2_filter_parser.attr_paths import AttrPath
|
||||||
|
|
||||||
|
from zerver.actions.create_user import do_create_user, do_reactivate_user
|
||||||
from zerver.actions.user_settings import check_change_full_name, do_change_user_delivery_email
|
from zerver.actions.user_settings import check_change_full_name, do_change_user_delivery_email
|
||||||
from zerver.actions.users import do_deactivate_user
|
from zerver.actions.users import do_deactivate_user
|
||||||
from zerver.lib.actions import do_create_user, do_reactivate_user
|
|
||||||
from zerver.lib.email_validation import email_allowed_for_realm, validate_email_not_already_in_realm
|
from zerver.lib.email_validation import email_allowed_for_realm, validate_email_not_already_in_realm
|
||||||
from zerver.lib.request import RequestNotes
|
from zerver.lib.request import RequestNotes
|
||||||
from zerver.lib.subdomains import get_subdomain
|
from zerver.lib.subdomains import get_subdomain
|
||||||
|
|
|
@ -3,7 +3,8 @@ from typing import Any
|
||||||
|
|
||||||
from django.core.management.base import CommandError
|
from django.core.management.base import CommandError
|
||||||
|
|
||||||
from zerver.lib.actions import do_create_realm, do_create_user
|
from zerver.actions.create_user import do_create_user
|
||||||
|
from zerver.lib.actions import do_create_realm
|
||||||
from zerver.lib.management import ZulipBaseCommand
|
from zerver.lib.management import ZulipBaseCommand
|
||||||
from zerver.models import UserProfile
|
from zerver.models import UserProfile
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ from typing import Any
|
||||||
from django.core.management.base import CommandError
|
from django.core.management.base import CommandError
|
||||||
from django.db.utils import IntegrityError
|
from django.db.utils import IntegrityError
|
||||||
|
|
||||||
from zerver.lib.actions import do_create_user
|
from zerver.actions.create_user import do_create_user
|
||||||
from zerver.lib.management import ZulipBaseCommand
|
from zerver.lib.management import ZulipBaseCommand
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -10,10 +10,11 @@ from typing import Any, Callable, Dict, List, Optional, Set, Tuple
|
||||||
|
|
||||||
from django.utils.timezone import now as timezone_now
|
from django.utils.timezone import now as timezone_now
|
||||||
|
|
||||||
|
from zerver.actions.create_user import do_create_user
|
||||||
from zerver.actions.presence import update_user_presence
|
from zerver.actions.presence import update_user_presence
|
||||||
from zerver.actions.realm_linkifiers import do_add_linkifier
|
from zerver.actions.realm_linkifiers import do_add_linkifier
|
||||||
from zerver.actions.realm_playgrounds import do_add_realm_playground
|
from zerver.actions.realm_playgrounds import do_add_realm_playground
|
||||||
from zerver.lib.actions import do_add_reaction, do_create_user
|
from zerver.lib.actions import do_add_reaction
|
||||||
from zerver.lib.events import do_events_register
|
from zerver.lib.events import do_events_register
|
||||||
from zerver.lib.initial_password import initial_password
|
from zerver.lib.initial_password import initial_password
|
||||||
from zerver.lib.test_classes import ZulipTestCase
|
from zerver.lib.test_classes import ZulipTestCase
|
||||||
|
|
|
@ -6,6 +6,11 @@ from django.contrib.auth.password_validation import validate_password
|
||||||
from django.utils.timezone import now as timezone_now
|
from django.utils.timezone import now as timezone_now
|
||||||
|
|
||||||
from analytics.models import StreamCount
|
from analytics.models import StreamCount
|
||||||
|
from zerver.actions.create_user import (
|
||||||
|
do_activate_mirror_dummy_user,
|
||||||
|
do_create_user,
|
||||||
|
do_reactivate_user,
|
||||||
|
)
|
||||||
from zerver.actions.realm_icon import do_change_icon_source
|
from zerver.actions.realm_icon import do_change_icon_source
|
||||||
from zerver.actions.realm_playgrounds import do_add_realm_playground, do_remove_realm_playground
|
from zerver.actions.realm_playgrounds import do_add_realm_playground, do_remove_realm_playground
|
||||||
from zerver.actions.streams import (
|
from zerver.actions.streams import (
|
||||||
|
@ -25,17 +30,14 @@ from zerver.actions.user_settings import (
|
||||||
)
|
)
|
||||||
from zerver.actions.users import do_change_user_role, do_deactivate_user
|
from zerver.actions.users import do_change_user_role, do_deactivate_user
|
||||||
from zerver.lib.actions import (
|
from zerver.lib.actions import (
|
||||||
do_activate_mirror_dummy_user,
|
|
||||||
do_add_realm_domain,
|
do_add_realm_domain,
|
||||||
do_change_bot_owner,
|
do_change_bot_owner,
|
||||||
do_change_default_all_public_streams,
|
do_change_default_all_public_streams,
|
||||||
do_change_default_events_register_stream,
|
do_change_default_events_register_stream,
|
||||||
do_change_default_sending_stream,
|
do_change_default_sending_stream,
|
||||||
do_change_realm_domain,
|
do_change_realm_domain,
|
||||||
do_create_user,
|
|
||||||
do_deactivate_realm,
|
do_deactivate_realm,
|
||||||
do_reactivate_realm,
|
do_reactivate_realm,
|
||||||
do_reactivate_user,
|
|
||||||
do_remove_realm_domain,
|
do_remove_realm_domain,
|
||||||
do_set_realm_authentication_methods,
|
do_set_realm_authentication_methods,
|
||||||
do_set_realm_message_editing,
|
do_set_realm_message_editing,
|
||||||
|
|
|
@ -40,15 +40,14 @@ from social_django.storage import BaseDjangoStorage
|
||||||
from social_django.strategy import DjangoStrategy
|
from social_django.strategy import DjangoStrategy
|
||||||
|
|
||||||
from confirmation.models import Confirmation, create_confirmation_link
|
from confirmation.models import Confirmation, create_confirmation_link
|
||||||
|
from zerver.actions.create_user import do_create_user, do_reactivate_user
|
||||||
from zerver.actions.invites import do_invite_users
|
from zerver.actions.invites import do_invite_users
|
||||||
from zerver.actions.user_settings import do_change_password
|
from zerver.actions.user_settings import do_change_password
|
||||||
from zerver.actions.users import change_user_is_active, do_deactivate_user
|
from zerver.actions.users import change_user_is_active, do_deactivate_user
|
||||||
from zerver.lib.actions import (
|
from zerver.lib.actions import (
|
||||||
do_create_realm,
|
do_create_realm,
|
||||||
do_create_user,
|
|
||||||
do_deactivate_realm,
|
do_deactivate_realm,
|
||||||
do_reactivate_realm,
|
do_reactivate_realm,
|
||||||
do_reactivate_user,
|
|
||||||
do_set_realm_property,
|
do_set_realm_property,
|
||||||
)
|
)
|
||||||
from zerver.lib.avatar import avatar_url
|
from zerver.lib.avatar import avatar_url
|
||||||
|
|
|
@ -14,6 +14,7 @@ from django.core.exceptions import ValidationError
|
||||||
from django.http import HttpRequest, HttpResponse
|
from django.http import HttpRequest, HttpResponse
|
||||||
from django.utils.timezone import now as timezone_now
|
from django.utils.timezone import now as timezone_now
|
||||||
|
|
||||||
|
from zerver.actions.create_user import do_reactivate_user
|
||||||
from zerver.actions.users import change_user_is_active, do_deactivate_user
|
from zerver.actions.users import change_user_is_active, do_deactivate_user
|
||||||
from zerver.decorator import (
|
from zerver.decorator import (
|
||||||
authenticate_notify,
|
authenticate_notify,
|
||||||
|
@ -33,7 +34,6 @@ from zerver.lib.actions import (
|
||||||
do_create_realm,
|
do_create_realm,
|
||||||
do_deactivate_realm,
|
do_deactivate_realm,
|
||||||
do_reactivate_realm,
|
do_reactivate_realm,
|
||||||
do_reactivate_user,
|
|
||||||
do_set_realm_property,
|
do_set_realm_property,
|
||||||
)
|
)
|
||||||
from zerver.lib.cache import dict_to_items_tuple, ignore_unhashable_lru_cache, items_tuple_to_dict
|
from zerver.lib.cache import dict_to_items_tuple, ignore_unhashable_lru_cache, items_tuple_to_dict
|
||||||
|
|
|
@ -7,7 +7,7 @@ from django.test import override_settings
|
||||||
from django.utils.timezone import now as timezone_now
|
from django.utils.timezone import now as timezone_now
|
||||||
|
|
||||||
from confirmation.models import one_click_unsubscribe_link
|
from confirmation.models import one_click_unsubscribe_link
|
||||||
from zerver.lib.actions import do_create_user
|
from zerver.actions.create_user import do_create_user
|
||||||
from zerver.lib.digest import (
|
from zerver.lib.digest import (
|
||||||
DigestTopic,
|
DigestTopic,
|
||||||
_enqueue_emails_for_realm,
|
_enqueue_emails_for_realm,
|
||||||
|
|
|
@ -14,6 +14,7 @@ import orjson
|
||||||
from django.utils.timezone import now as timezone_now
|
from django.utils.timezone import now as timezone_now
|
||||||
|
|
||||||
from zerver.actions.alert_words import do_add_alert_words, do_remove_alert_words
|
from zerver.actions.alert_words import do_add_alert_words, do_remove_alert_words
|
||||||
|
from zerver.actions.create_user import do_create_user, do_reactivate_user
|
||||||
from zerver.actions.custom_profile_fields import (
|
from zerver.actions.custom_profile_fields import (
|
||||||
do_remove_realm_custom_profile_field,
|
do_remove_realm_custom_profile_field,
|
||||||
do_update_user_custom_profile_data_if_changed,
|
do_update_user_custom_profile_data_if_changed,
|
||||||
|
@ -93,11 +94,9 @@ from zerver.lib.actions import (
|
||||||
do_change_default_sending_stream,
|
do_change_default_sending_stream,
|
||||||
do_change_realm_domain,
|
do_change_realm_domain,
|
||||||
do_change_realm_plan_type,
|
do_change_realm_plan_type,
|
||||||
do_create_user,
|
|
||||||
do_deactivate_realm,
|
do_deactivate_realm,
|
||||||
do_delete_messages,
|
do_delete_messages,
|
||||||
do_mute_user,
|
do_mute_user,
|
||||||
do_reactivate_user,
|
|
||||||
do_remove_reaction,
|
do_remove_reaction,
|
||||||
do_remove_realm_domain,
|
do_remove_realm_domain,
|
||||||
do_set_realm_authentication_methods,
|
do_set_realm_authentication_methods,
|
||||||
|
|
|
@ -13,8 +13,9 @@ from django.test import override_settings
|
||||||
from django.utils.timezone import now as timezone_now
|
from django.utils.timezone import now as timezone_now
|
||||||
|
|
||||||
from corporate.models import Customer, CustomerPlan
|
from corporate.models import Customer, CustomerPlan
|
||||||
|
from zerver.actions.create_user import do_create_user
|
||||||
from zerver.actions.users import change_user_is_active
|
from zerver.actions.users import change_user_is_active
|
||||||
from zerver.lib.actions import do_change_realm_plan_type, do_create_user
|
from zerver.lib.actions import do_change_realm_plan_type
|
||||||
from zerver.lib.compatibility import LAST_SERVER_UPGRADE_TIME, is_outdated_server
|
from zerver.lib.compatibility import LAST_SERVER_UPGRADE_TIME, is_outdated_server
|
||||||
from zerver.lib.home import (
|
from zerver.lib.home import (
|
||||||
get_billing_info,
|
get_billing_info,
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
|
from zerver.actions.create_user import do_create_user
|
||||||
from zerver.actions.hotspots import do_mark_hotspot_as_read
|
from zerver.actions.hotspots import do_mark_hotspot_as_read
|
||||||
from zerver.lib.actions import do_create_user
|
|
||||||
from zerver.lib.hotspots import ALL_HOTSPOTS, INTRO_HOTSPOTS, get_next_hotspots
|
from zerver.lib.hotspots import ALL_HOTSPOTS, INTRO_HOTSPOTS, get_next_hotspots
|
||||||
from zerver.lib.test_classes import ZulipTestCase
|
from zerver.lib.test_classes import ZulipTestCase
|
||||||
from zerver.models import UserHotspot, UserProfile, get_realm
|
from zerver.models import UserHotspot, UserProfile, get_realm
|
||||||
|
|
|
@ -11,6 +11,7 @@ from django.utils.timezone import now as timezone_now
|
||||||
|
|
||||||
from analytics.models import UserCount
|
from analytics.models import UserCount
|
||||||
from zerver.actions.alert_words import do_add_alert_words
|
from zerver.actions.alert_words import do_add_alert_words
|
||||||
|
from zerver.actions.create_user import do_create_user
|
||||||
from zerver.actions.custom_profile_fields import (
|
from zerver.actions.custom_profile_fields import (
|
||||||
do_update_user_custom_profile_data_if_changed,
|
do_update_user_custom_profile_data_if_changed,
|
||||||
try_add_realm_custom_profile_field,
|
try_add_realm_custom_profile_field,
|
||||||
|
@ -27,7 +28,6 @@ from zerver.lib.actions import (
|
||||||
check_add_reaction,
|
check_add_reaction,
|
||||||
do_add_reaction,
|
do_add_reaction,
|
||||||
do_change_realm_plan_type,
|
do_change_realm_plan_type,
|
||||||
do_create_user,
|
|
||||||
do_mute_user,
|
do_mute_user,
|
||||||
)
|
)
|
||||||
from zerver.lib.avatar_hash import user_avatar_path
|
from zerver.lib.avatar_hash import user_avatar_path
|
||||||
|
|
|
@ -13,7 +13,8 @@ from django.test import override_settings
|
||||||
from django.utils.timezone import now as timezone_now
|
from django.utils.timezone import now as timezone_now
|
||||||
|
|
||||||
from confirmation.models import RealmCreationKey, generate_realm_creation_url
|
from confirmation.models import RealmCreationKey, generate_realm_creation_url
|
||||||
from zerver.lib.actions import do_add_reaction, do_create_user
|
from zerver.actions.create_user import do_create_user
|
||||||
|
from zerver.lib.actions import do_add_reaction
|
||||||
from zerver.lib.management import ZulipBaseCommand, check_config
|
from zerver.lib.management import ZulipBaseCommand, check_config
|
||||||
from zerver.lib.test_classes import ZulipTestCase
|
from zerver.lib.test_classes import ZulipTestCase
|
||||||
from zerver.lib.test_helpers import most_recent_message, stdout_suppressed
|
from zerver.lib.test_helpers import most_recent_message, stdout_suppressed
|
||||||
|
|
|
@ -10,6 +10,7 @@ from django.http import HttpResponse
|
||||||
from django.test import override_settings
|
from django.test import override_settings
|
||||||
from django.utils.timezone import now as timezone_now
|
from django.utils.timezone import now as timezone_now
|
||||||
|
|
||||||
|
from zerver.actions.create_user import do_create_user
|
||||||
from zerver.actions.message_send import (
|
from zerver.actions.message_send import (
|
||||||
build_message_send_dict,
|
build_message_send_dict,
|
||||||
check_message,
|
check_message,
|
||||||
|
@ -27,12 +28,7 @@ from zerver.actions.message_send import (
|
||||||
)
|
)
|
||||||
from zerver.actions.streams import do_change_stream_post_policy
|
from zerver.actions.streams import do_change_stream_post_policy
|
||||||
from zerver.actions.users import do_change_can_forge_sender, do_deactivate_user
|
from zerver.actions.users import do_change_can_forge_sender, do_deactivate_user
|
||||||
from zerver.lib.actions import (
|
from zerver.lib.actions import do_add_realm_domain, do_create_realm, do_set_realm_property
|
||||||
do_add_realm_domain,
|
|
||||||
do_create_realm,
|
|
||||||
do_create_user,
|
|
||||||
do_set_realm_property,
|
|
||||||
)
|
|
||||||
from zerver.lib.addressee import Addressee
|
from zerver.lib.addressee import Addressee
|
||||||
from zerver.lib.cache import cache_delete, get_stream_cache_key
|
from zerver.lib.cache import cache_delete, get_stream_cache_key
|
||||||
from zerver.lib.exceptions import JsonableError
|
from zerver.lib.exceptions import JsonableError
|
||||||
|
|
|
@ -8,8 +8,8 @@ from django.core import mail
|
||||||
from django.test import override_settings
|
from django.test import override_settings
|
||||||
|
|
||||||
from corporate.lib.stripe import get_latest_seat_count
|
from corporate.lib.stripe import get_latest_seat_count
|
||||||
|
from zerver.actions.create_user import notify_new_user
|
||||||
from zerver.actions.user_settings import do_change_user_setting
|
from zerver.actions.user_settings import do_change_user_setting
|
||||||
from zerver.lib.actions import notify_new_user
|
|
||||||
from zerver.lib.initial_password import initial_password
|
from zerver.lib.initial_password import initial_password
|
||||||
from zerver.lib.streams import create_stream_if_needed
|
from zerver.lib.streams import create_stream_if_needed
|
||||||
from zerver.lib.test_classes import ZulipTestCase
|
from zerver.lib.test_classes import ZulipTestCase
|
||||||
|
|
|
@ -6,7 +6,7 @@ import requests
|
||||||
import responses
|
import responses
|
||||||
|
|
||||||
from version import ZULIP_VERSION
|
from version import ZULIP_VERSION
|
||||||
from zerver.lib.actions import do_create_user
|
from zerver.actions.create_user import do_create_user
|
||||||
from zerver.lib.outgoing_webhook import (
|
from zerver.lib.outgoing_webhook import (
|
||||||
GenericOutgoingWebhookService,
|
GenericOutgoingWebhookService,
|
||||||
SlackOutgoingWebhookService,
|
SlackOutgoingWebhookService,
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
|
|
||||||
|
from zerver.actions.create_user import do_create_user
|
||||||
from zerver.actions.realm_emoji import check_add_realm_emoji
|
from zerver.actions.realm_emoji import check_add_realm_emoji
|
||||||
from zerver.actions.users import do_change_user_role
|
from zerver.actions.users import do_change_user_role
|
||||||
from zerver.lib.actions import do_create_realm, do_create_user, do_set_realm_property
|
from zerver.lib.actions import do_create_realm, do_set_realm_property
|
||||||
from zerver.lib.exceptions import JsonableError
|
from zerver.lib.exceptions import JsonableError
|
||||||
from zerver.lib.test_classes import ZulipTestCase
|
from zerver.lib.test_classes import ZulipTestCase
|
||||||
from zerver.lib.test_helpers import get_test_image_file
|
from zerver.lib.test_helpers import get_test_image_file
|
||||||
|
|
|
@ -6,8 +6,8 @@ import orjson
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.test import override_settings
|
from django.test import override_settings
|
||||||
|
|
||||||
|
from zerver.actions.create_user import do_create_user
|
||||||
from zerver.actions.message_send import get_service_bot_events
|
from zerver.actions.message_send import get_service_bot_events
|
||||||
from zerver.lib.actions import do_create_user
|
|
||||||
from zerver.lib.bot_config import ConfigError, load_bot_config_template, set_bot_config
|
from zerver.lib.bot_config import ConfigError, load_bot_config_template, set_bot_config
|
||||||
from zerver.lib.bot_lib import EmbeddedBotEmptyRecipientsList, EmbeddedBotHandler, StateHandler
|
from zerver.lib.bot_lib import EmbeddedBotEmptyRecipientsList, EmbeddedBotHandler, StateHandler
|
||||||
from zerver.lib.bot_storage import StateError
|
from zerver.lib.bot_storage import StateError
|
||||||
|
|
|
@ -25,6 +25,7 @@ from confirmation.models import (
|
||||||
one_click_unsubscribe_link,
|
one_click_unsubscribe_link,
|
||||||
)
|
)
|
||||||
from corporate.lib.stripe import get_latest_seat_count
|
from corporate.lib.stripe import get_latest_seat_count
|
||||||
|
from zerver.actions.create_user import add_new_user_history, do_create_user, process_new_human_user
|
||||||
from zerver.actions.default_streams import (
|
from zerver.actions.default_streams import (
|
||||||
do_add_default_stream,
|
do_add_default_stream,
|
||||||
do_create_default_stream_group,
|
do_create_default_stream_group,
|
||||||
|
@ -41,14 +42,11 @@ from zerver.context_processors import common_context
|
||||||
from zerver.decorator import do_two_factor_login
|
from zerver.decorator import do_two_factor_login
|
||||||
from zerver.forms import HomepageForm, check_subdomain_available
|
from zerver.forms import HomepageForm, check_subdomain_available
|
||||||
from zerver.lib.actions import (
|
from zerver.lib.actions import (
|
||||||
add_new_user_history,
|
|
||||||
do_change_realm_subdomain,
|
do_change_realm_subdomain,
|
||||||
do_create_realm,
|
do_create_realm,
|
||||||
do_create_user,
|
|
||||||
do_deactivate_realm,
|
do_deactivate_realm,
|
||||||
do_set_realm_property,
|
do_set_realm_property,
|
||||||
do_set_realm_user_default_setting,
|
do_set_realm_user_default_setting,
|
||||||
process_new_human_user,
|
|
||||||
)
|
)
|
||||||
from zerver.lib.email_notifications import enqueue_welcome_emails, followup_day2_email_delay
|
from zerver.lib.email_notifications import enqueue_welcome_emails, followup_day2_email_delay
|
||||||
from zerver.lib.initial_password import initial_password
|
from zerver.lib.initial_password import initial_password
|
||||||
|
@ -253,7 +251,7 @@ class AddNewUserHistoryTest(ZulipTestCase):
|
||||||
self.send_stream_message(self.example_user("hamlet"), stream.name, "test 2")
|
self.send_stream_message(self.example_user("hamlet"), stream.name, "test 2")
|
||||||
self.send_stream_message(self.example_user("hamlet"), stream.name, "test 3")
|
self.send_stream_message(self.example_user("hamlet"), stream.name, "test 3")
|
||||||
|
|
||||||
with patch("zerver.lib.actions.add_new_user_history"):
|
with patch("zerver.actions.create_user.add_new_user_history"):
|
||||||
self.register(self.nonreg_email("test"), "test")
|
self.register(self.nonreg_email("test"), "test")
|
||||||
user_profile = self.nonreg_user("test")
|
user_profile = self.nonreg_user("test")
|
||||||
subs = Subscription.objects.select_related("recipient").filter(
|
subs = Subscription.objects.select_related("recipient").filter(
|
||||||
|
@ -269,7 +267,9 @@ class AddNewUserHistoryTest(ZulipTestCase):
|
||||||
|
|
||||||
# Overwrite ONBOARDING_UNREAD_MESSAGES to 2
|
# Overwrite ONBOARDING_UNREAD_MESSAGES to 2
|
||||||
ONBOARDING_UNREAD_MESSAGES = 2
|
ONBOARDING_UNREAD_MESSAGES = 2
|
||||||
with patch("zerver.lib.actions.ONBOARDING_UNREAD_MESSAGES", ONBOARDING_UNREAD_MESSAGES):
|
with patch(
|
||||||
|
"zerver.actions.create_user.ONBOARDING_UNREAD_MESSAGES", ONBOARDING_UNREAD_MESSAGES
|
||||||
|
):
|
||||||
add_new_user_history(user_profile, streams)
|
add_new_user_history(user_profile, streams)
|
||||||
|
|
||||||
# Our first message is in the user's history
|
# Our first message is in the user's history
|
||||||
|
|
|
@ -12,6 +12,7 @@ from django.test import override_settings
|
||||||
from django.utils.timezone import now as timezone_now
|
from django.utils.timezone import now as timezone_now
|
||||||
|
|
||||||
from confirmation.models import Confirmation
|
from confirmation.models import Confirmation
|
||||||
|
from zerver.actions.create_user import do_create_user, do_reactivate_user
|
||||||
from zerver.actions.invites import do_create_multiuse_invite_link, do_invite_users
|
from zerver.actions.invites import do_create_multiuse_invite_link, do_invite_users
|
||||||
from zerver.actions.message_send import get_recipient_info
|
from zerver.actions.message_send import get_recipient_info
|
||||||
from zerver.actions.users import (
|
from zerver.actions.users import (
|
||||||
|
@ -21,12 +22,7 @@ from zerver.actions.users import (
|
||||||
do_deactivate_user,
|
do_deactivate_user,
|
||||||
do_delete_user,
|
do_delete_user,
|
||||||
)
|
)
|
||||||
from zerver.lib.actions import (
|
from zerver.lib.actions import do_mute_user, do_set_realm_property
|
||||||
do_create_user,
|
|
||||||
do_mute_user,
|
|
||||||
do_reactivate_user,
|
|
||||||
do_set_realm_property,
|
|
||||||
)
|
|
||||||
from zerver.lib.avatar import avatar_url, get_gravatar_url
|
from zerver.lib.avatar import avatar_url, get_gravatar_url
|
||||||
from zerver.lib.bulk_create import create_users
|
from zerver.lib.bulk_create import create_users
|
||||||
from zerver.lib.create_user import copy_default_settings
|
from zerver.lib.create_user import copy_default_settings
|
||||||
|
|
|
@ -25,6 +25,7 @@ from confirmation.models import (
|
||||||
render_confirmation_key_error,
|
render_confirmation_key_error,
|
||||||
validate_key,
|
validate_key,
|
||||||
)
|
)
|
||||||
|
from zerver.actions.create_user import do_activate_mirror_dummy_user, do_create_user
|
||||||
from zerver.actions.default_streams import lookup_default_stream_groups
|
from zerver.actions.default_streams import lookup_default_stream_groups
|
||||||
from zerver.actions.user_settings import (
|
from zerver.actions.user_settings import (
|
||||||
do_change_full_name,
|
do_change_full_name,
|
||||||
|
@ -40,7 +41,7 @@ from zerver.forms import (
|
||||||
RealmRedirectForm,
|
RealmRedirectForm,
|
||||||
RegistrationForm,
|
RegistrationForm,
|
||||||
)
|
)
|
||||||
from zerver.lib.actions import do_activate_mirror_dummy_user, do_create_realm, do_create_user
|
from zerver.lib.actions import do_create_realm
|
||||||
from zerver.lib.email_validation import email_allowed_for_realm, validate_email_not_already_in_realm
|
from zerver.lib.email_validation import email_allowed_for_realm, validate_email_not_already_in_realm
|
||||||
from zerver.lib.exceptions import RateLimited
|
from zerver.lib.exceptions import RateLimited
|
||||||
from zerver.lib.pysa import mark_sanitized
|
from zerver.lib.pysa import mark_sanitized
|
||||||
|
|
|
@ -6,6 +6,7 @@ from django.http import HttpRequest, HttpResponse
|
||||||
from django.shortcuts import redirect
|
from django.shortcuts import redirect
|
||||||
from django.utils.translation import gettext as _
|
from django.utils.translation import gettext as _
|
||||||
|
|
||||||
|
from zerver.actions.create_user import do_create_user, do_reactivate_user, notify_created_bot
|
||||||
from zerver.actions.custom_profile_fields import (
|
from zerver.actions.custom_profile_fields import (
|
||||||
check_remove_custom_profile_field_value,
|
check_remove_custom_profile_field_value,
|
||||||
do_update_user_custom_profile_data_if_changed,
|
do_update_user_custom_profile_data_if_changed,
|
||||||
|
@ -30,9 +31,6 @@ from zerver.lib.actions import (
|
||||||
do_change_default_all_public_streams,
|
do_change_default_all_public_streams,
|
||||||
do_change_default_events_register_stream,
|
do_change_default_events_register_stream,
|
||||||
do_change_default_sending_stream,
|
do_change_default_sending_stream,
|
||||||
do_create_user,
|
|
||||||
do_reactivate_user,
|
|
||||||
notify_created_bot,
|
|
||||||
)
|
)
|
||||||
from zerver.lib.avatar import avatar_url, get_gravatar_url
|
from zerver.lib.avatar import avatar_url, get_gravatar_url
|
||||||
from zerver.lib.bot_config import set_bot_config
|
from zerver.lib.bot_config import set_bot_config
|
||||||
|
|
|
@ -2,10 +2,11 @@ from typing import Any, Dict, List
|
||||||
|
|
||||||
from django.core.management.base import BaseCommand
|
from django.core.management.base import BaseCommand
|
||||||
|
|
||||||
|
from zerver.actions.create_user import do_create_user
|
||||||
from zerver.actions.message_send import do_send_messages, internal_prep_stream_message
|
from zerver.actions.message_send import do_send_messages, internal_prep_stream_message
|
||||||
from zerver.actions.streams import bulk_add_subscriptions
|
from zerver.actions.streams import bulk_add_subscriptions
|
||||||
from zerver.actions.user_settings import do_change_avatar_fields
|
from zerver.actions.user_settings import do_change_avatar_fields
|
||||||
from zerver.lib.actions import do_add_reaction, do_create_user
|
from zerver.lib.actions import do_add_reaction
|
||||||
from zerver.lib.emoji import emoji_name_to_emoji_code
|
from zerver.lib.emoji import emoji_name_to_emoji_code
|
||||||
from zerver.lib.streams import ensure_stream
|
from zerver.lib.streams import ensure_stream
|
||||||
from zerver.lib.upload import upload_avatar_image
|
from zerver.lib.upload import upload_avatar_image
|
||||||
|
|
|
@ -58,11 +58,11 @@ from social_core.pipeline.partial import partial
|
||||||
from typing_extensions import TypedDict
|
from typing_extensions import TypedDict
|
||||||
from zxcvbn import zxcvbn
|
from zxcvbn import zxcvbn
|
||||||
|
|
||||||
|
from zerver.actions.create_user import do_create_user, do_reactivate_user
|
||||||
from zerver.actions.custom_profile_fields import do_update_user_custom_profile_data_if_changed
|
from zerver.actions.custom_profile_fields import do_update_user_custom_profile_data_if_changed
|
||||||
from zerver.actions.user_settings import do_regenerate_api_key
|
from zerver.actions.user_settings import do_regenerate_api_key
|
||||||
from zerver.actions.users import do_deactivate_user
|
from zerver.actions.users import do_deactivate_user
|
||||||
from zerver.decorator import client_is_exempt_from_rate_limiting
|
from zerver.decorator import client_is_exempt_from_rate_limiting
|
||||||
from zerver.lib.actions import do_create_user, do_reactivate_user
|
|
||||||
from zerver.lib.avatar import avatar_url, is_avatar_new
|
from zerver.lib.avatar import avatar_url, is_avatar_new
|
||||||
from zerver.lib.avatar_hash import user_avatar_content_hash
|
from zerver.lib.avatar_hash import user_avatar_content_hash
|
||||||
from zerver.lib.dev_ldap_directory import init_fakeldap
|
from zerver.lib.dev_ldap_directory import init_fakeldap
|
||||||
|
|
Loading…
Reference in New Issue