diff --git a/analytics/management/commands/populate_analytics_db.py b/analytics/management/commands/populate_analytics_db.py index 99b73f72cc..fb8f16f6eb 100644 --- a/analytics/management/commands/populate_analytics_db.py +++ b/analytics/management/commands/populate_analytics_db.py @@ -16,7 +16,8 @@ from analytics.models import ( StreamCount, UserCount, ) -from zerver.lib.actions import do_change_user_role, do_create_realm +from zerver.actions.users import do_change_user_role +from zerver.lib.actions import do_create_realm from zerver.lib.create_user import create_user from zerver.lib.stream_color import STREAM_ASSIGNMENT_COLORS from zerver.lib.timestamp import floor_to_day diff --git a/analytics/tests/test_counts.py b/analytics/tests/test_counts.py index ca72728e03..1886bf2266 100644 --- a/analytics/tests/test_counts.py +++ b/analytics/tests/test_counts.py @@ -38,11 +38,11 @@ from zerver.actions.invites import ( do_revoke_user_invite, ) from zerver.actions.user_activity import update_user_activity_interval +from zerver.actions.users import do_deactivate_user from zerver.lib.actions import ( do_activate_mirror_dummy_user, do_create_realm, do_create_user, - do_deactivate_user, do_mark_all_as_read, do_mark_stream_messages_as_read, do_reactivate_user, diff --git a/corporate/lib/stripe.py b/corporate/lib/stripe.py index cefe38a1cd..ce4079ca6f 100644 --- a/corporate/lib/stripe.py +++ b/corporate/lib/stripe.py @@ -325,7 +325,7 @@ def do_create_stripe_customer(user: UserProfile, payment_method: Optional[str] = customer, created = Customer.objects.update_or_create( realm=realm, defaults={"stripe_customer_id": stripe_customer.id} ) - from zerver.lib.actions import do_make_user_billing_admin + from zerver.actions.users import do_make_user_billing_admin do_make_user_billing_admin(user) return customer diff --git a/corporate/tests/test_stripe.py b/corporate/tests/test_stripe.py index e2bc2600b9..548dd333bc 100644 --- a/corporate/tests/test_stripe.py +++ b/corporate/tests/test_stripe.py @@ -81,12 +81,12 @@ from corporate.models import ( get_current_plan_by_realm, get_customer_by_realm, ) +from zerver.actions.users import do_deactivate_user from zerver.lib.actions import ( do_activate_mirror_dummy_user, do_create_realm, do_create_user, do_deactivate_realm, - do_deactivate_user, do_reactivate_realm, do_reactivate_user, ) diff --git a/corporate/views/upgrade.py b/corporate/views/upgrade.py index d50532663a..f5ee4028e2 100644 --- a/corporate/views/upgrade.py +++ b/corporate/views/upgrade.py @@ -37,8 +37,8 @@ from corporate.models import ( get_customer_by_realm, ) from corporate.views.billing_page import billing_home +from zerver.actions.users import do_make_user_billing_admin from zerver.decorator import require_organization_member, zulip_login_required -from zerver.lib.actions import do_make_user_billing_admin from zerver.lib.request import REQ, has_request_variables from zerver.lib.response import json_success from zerver.lib.send_email import FromAddress, send_email diff --git a/tools/test-api b/tools/test-api index 70d1e7465a..77cd6ac90f 100755 --- a/tools/test-api +++ b/tools/test-api @@ -31,8 +31,8 @@ with test_server_running( ): # zerver imports should happen after `django.setup()` is run # by the test_server_running decorator. + from zerver.actions.users import change_user_is_active from zerver.lib.actions import ( - change_user_is_active, do_create_user, do_deactivate_realm, do_reactivate_realm, diff --git a/zerver/actions/users.py b/zerver/actions/users.py new file mode 100644 index 0000000000..703a84f2ba --- /dev/null +++ b/zerver/actions/users.py @@ -0,0 +1,383 @@ +from collections import defaultdict +from typing import Any, Dict, List, Optional + +import orjson +from django.conf import settings +from django.db import transaction +from django.utils.timezone import now as timezone_now + +from analytics.lib.counts import COUNT_STATS, do_increment_logging_stat +from zerver.actions.invites import revoke_invites_generated_by_user +from zerver.actions.user_groups import ( + do_send_user_group_members_update_event, + update_users_in_full_members_system_group, +) +from zerver.lib.avatar import avatar_url_from_dict +from zerver.lib.bot_config import ConfigError, get_bot_config, get_bot_configs, set_bot_config +from zerver.lib.cache import bot_dict_fields +from zerver.lib.create_user import create_user +from zerver.lib.send_email import clear_scheduled_emails +from zerver.lib.sessions import delete_user_sessions +from zerver.lib.user_counts import realm_user_count_by_role +from zerver.lib.user_groups import get_system_user_group_for_user +from zerver.lib.users import get_active_bots_owned_by_user +from zerver.models import ( + Realm, + RealmAuditLog, + Recipient, + Service, + Subscription, + UserGroupMembership, + UserProfile, + active_user_ids, + bot_owner_user_ids, + get_bot_dicts_in_realm, + get_bot_services, + get_fake_email_domain, + get_user_profile_by_id, +) +from zerver.tornado.django_api import send_event + +if settings.BILLING_ENABLED: + from corporate.lib.stripe import update_license_ledger_if_needed + + +def do_delete_user(user_profile: UserProfile) -> None: + if user_profile.realm.is_zephyr_mirror_realm: + raise AssertionError("Deleting zephyr mirror users is not supported") + + do_deactivate_user(user_profile, acting_user=None) + + subscribed_huddle_recipient_ids = set( + Subscription.objects.filter( + user_profile=user_profile, recipient__type=Recipient.HUDDLE + ).values_list("recipient_id", flat=True) + ) + user_id = user_profile.id + realm = user_profile.realm + date_joined = user_profile.date_joined + personal_recipient = user_profile.recipient + + with transaction.atomic(): + user_profile.delete() + # Recipient objects don't get deleted through CASCADE, so we need to handle + # the user's personal recipient manually. This will also delete all Messages pointing + # to this recipient (all private messages sent to the user). + assert personal_recipient is not None + personal_recipient.delete() + replacement_user = create_user( + force_id=user_id, + email=f"deleteduser{user_id}@{get_fake_email_domain(realm)}", + password=None, + realm=realm, + full_name=f"Deleted User {user_id}", + active=False, + is_mirror_dummy=True, + force_date_joined=date_joined, + ) + subs_to_recreate = [ + Subscription( + user_profile=replacement_user, + recipient=recipient, + is_user_active=replacement_user.is_active, + ) + for recipient in Recipient.objects.filter(id__in=subscribed_huddle_recipient_ids) + ] + Subscription.objects.bulk_create(subs_to_recreate) + + RealmAuditLog.objects.create( + realm=replacement_user.realm, + modified_user=replacement_user, + acting_user=None, + event_type=RealmAuditLog.USER_DELETED, + event_time=timezone_now(), + ) + + +def change_user_is_active(user_profile: UserProfile, value: bool) -> None: + """ + Helper function for changing the .is_active field. Not meant as a standalone function + in production code as properly activating/deactivating users requires more steps. + This changes the is_active value and saves it, while ensuring + Subscription.is_user_active values are updated in the same db transaction. + """ + with transaction.atomic(savepoint=False): + user_profile.is_active = value + user_profile.save(update_fields=["is_active"]) + Subscription.objects.filter(user_profile=user_profile).update(is_user_active=value) + + +def do_deactivate_user( + user_profile: UserProfile, _cascade: bool = True, *, acting_user: Optional[UserProfile] +) -> None: + if not user_profile.is_active: + return + + if _cascade: + # We need to deactivate bots before the target user, to ensure + # that a failure partway through this function cannot result + # in only the user being deactivated. + bot_profiles = get_active_bots_owned_by_user(user_profile) + for profile in bot_profiles: + do_deactivate_user(profile, _cascade=False, acting_user=acting_user) + + with transaction.atomic(): + if user_profile.realm.is_zephyr_mirror_realm: # nocoverage + # For zephyr mirror users, we need to make them a mirror dummy + # again; otherwise, other users won't get the correct behavior + # when trying to send messages to this person inside Zulip. + # + # Ideally, we need to also ensure their zephyr mirroring bot + # isn't running, but that's a separate issue. + user_profile.is_mirror_dummy = True + user_profile.save(update_fields=["is_mirror_dummy"]) + + change_user_is_active(user_profile, False) + + clear_scheduled_emails(user_profile.id) + revoke_invites_generated_by_user(user_profile) + + event_time = timezone_now() + RealmAuditLog.objects.create( + realm=user_profile.realm, + modified_user=user_profile, + acting_user=acting_user, + event_type=RealmAuditLog.USER_DEACTIVATED, + 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, + increment=-1, + ) + if settings.BILLING_ENABLED: + update_license_ledger_if_needed(user_profile.realm, event_time) + + delete_user_sessions(user_profile) + event = dict( + type="realm_user", + op="remove", + person=dict(user_id=user_profile.id, full_name=user_profile.full_name), + ) + send_event(user_profile.realm, event, active_user_ids(user_profile.realm_id)) + + if user_profile.is_bot: + event = dict( + type="realm_bot", + op="remove", + bot=dict(user_id=user_profile.id, full_name=user_profile.full_name), + ) + send_event(user_profile.realm, event, bot_owner_user_ids(user_profile)) + + +@transaction.atomic(durable=True) +def do_change_user_role( + user_profile: UserProfile, value: int, *, acting_user: Optional[UserProfile] +) -> None: + old_value = user_profile.role + old_system_group = get_system_user_group_for_user(user_profile) + + user_profile.role = value + user_profile.save(update_fields=["role"]) + RealmAuditLog.objects.create( + realm=user_profile.realm, + modified_user=user_profile, + acting_user=acting_user, + event_type=RealmAuditLog.USER_ROLE_CHANGED, + event_time=timezone_now(), + extra_data=orjson.dumps( + { + RealmAuditLog.OLD_VALUE: old_value, + RealmAuditLog.NEW_VALUE: value, + RealmAuditLog.ROLE_COUNT: realm_user_count_by_role(user_profile.realm), + } + ).decode(), + ) + event = dict( + type="realm_user", op="update", person=dict(user_id=user_profile.id, role=user_profile.role) + ) + transaction.on_commit( + lambda: send_event(user_profile.realm, event, active_user_ids(user_profile.realm_id)) + ) + + UserGroupMembership.objects.filter( + user_profile=user_profile, user_group=old_system_group + ).delete() + + system_group = get_system_user_group_for_user(user_profile) + UserGroupMembership.objects.create(user_profile=user_profile, user_group=system_group) + + do_send_user_group_members_update_event("remove_members", old_system_group, [user_profile.id]) + + do_send_user_group_members_update_event("add_members", system_group, [user_profile.id]) + + if UserProfile.ROLE_MEMBER in [old_value, value]: + update_users_in_full_members_system_group(user_profile.realm, [user_profile.id]) + + +def do_make_user_billing_admin(user_profile: UserProfile) -> None: + user_profile.is_billing_admin = True + user_profile.save(update_fields=["is_billing_admin"]) + event = dict( + type="realm_user", op="update", person=dict(user_id=user_profile.id, is_billing_admin=True) + ) + send_event(user_profile.realm, event, active_user_ids(user_profile.realm_id)) + + +def do_change_can_forge_sender(user_profile: UserProfile, value: bool) -> None: + user_profile.can_forge_sender = value + user_profile.save(update_fields=["can_forge_sender"]) + + +def do_change_can_create_users(user_profile: UserProfile, value: bool) -> None: + user_profile.can_create_users = value + user_profile.save(update_fields=["can_create_users"]) + + +def do_update_outgoing_webhook_service( + bot_profile: UserProfile, service_interface: int, service_payload_url: str +) -> None: + # TODO: First service is chosen because currently one bot can only have one service. + # Update this once multiple services are supported. + service = get_bot_services(bot_profile.id)[0] + service.base_url = service_payload_url + service.interface = service_interface + service.save() + send_event( + bot_profile.realm, + dict( + type="realm_bot", + op="update", + bot=dict( + user_id=bot_profile.id, + services=[ + dict( + base_url=service.base_url, interface=service.interface, token=service.token + ) + ], + ), + ), + bot_owner_user_ids(bot_profile), + ) + + +def do_update_bot_config_data(bot_profile: UserProfile, config_data: Dict[str, str]) -> None: + for key, value in config_data.items(): + set_bot_config(bot_profile, key, value) + updated_config_data = get_bot_config(bot_profile) + send_event( + bot_profile.realm, + dict( + type="realm_bot", + op="update", + bot=dict( + user_id=bot_profile.id, + services=[dict(config_data=updated_config_data)], + ), + ), + bot_owner_user_ids(bot_profile), + ) + + +def get_service_dicts_for_bot(user_profile_id: int) -> List[Dict[str, Any]]: + user_profile = get_user_profile_by_id(user_profile_id) + services = get_bot_services(user_profile_id) + service_dicts: List[Dict[str, Any]] = [] + if user_profile.bot_type == UserProfile.OUTGOING_WEBHOOK_BOT: + service_dicts = [ + { + "base_url": service.base_url, + "interface": service.interface, + "token": service.token, + } + for service in services + ] + elif user_profile.bot_type == UserProfile.EMBEDDED_BOT: + try: + service_dicts = [ + { + "config_data": get_bot_config(user_profile), + "service_name": services[0].name, + } + ] + # A ConfigError just means that there are no config entries for user_profile. + except ConfigError: + pass + return service_dicts + + +def get_service_dicts_for_bots( + bot_dicts: List[Dict[str, Any]], realm: Realm +) -> Dict[int, List[Dict[str, Any]]]: + bot_profile_ids = [bot_dict["id"] for bot_dict in bot_dicts] + bot_services_by_uid: Dict[int, List[Service]] = defaultdict(list) + for service in Service.objects.filter(user_profile_id__in=bot_profile_ids): + bot_services_by_uid[service.user_profile_id].append(service) + + embedded_bot_ids = [ + bot_dict["id"] for bot_dict in bot_dicts if bot_dict["bot_type"] == UserProfile.EMBEDDED_BOT + ] + embedded_bot_configs = get_bot_configs(embedded_bot_ids) + + service_dicts_by_uid: Dict[int, List[Dict[str, Any]]] = {} + for bot_dict in bot_dicts: + bot_profile_id = bot_dict["id"] + bot_type = bot_dict["bot_type"] + services = bot_services_by_uid[bot_profile_id] + service_dicts: List[Dict[str, Any]] = [] + if bot_type == UserProfile.OUTGOING_WEBHOOK_BOT: + service_dicts = [ + { + "base_url": service.base_url, + "interface": service.interface, + "token": service.token, + } + for service in services + ] + elif bot_type == UserProfile.EMBEDDED_BOT: + if bot_profile_id in embedded_bot_configs.keys(): + bot_config = embedded_bot_configs[bot_profile_id] + service_dicts = [ + { + "config_data": bot_config, + "service_name": services[0].name, + } + ] + service_dicts_by_uid[bot_profile_id] = service_dicts + return service_dicts_by_uid + + +def get_owned_bot_dicts( + user_profile: UserProfile, include_all_realm_bots_if_admin: bool = True +) -> List[Dict[str, Any]]: + if user_profile.is_realm_admin and include_all_realm_bots_if_admin: + result = get_bot_dicts_in_realm(user_profile.realm) + else: + result = UserProfile.objects.filter( + realm=user_profile.realm, is_bot=True, bot_owner=user_profile + ).values(*bot_dict_fields) + services_by_ids = get_service_dicts_for_bots(result, user_profile.realm) + return [ + { + "email": botdict["email"], + "user_id": botdict["id"], + "full_name": botdict["full_name"], + "bot_type": botdict["bot_type"], + "is_active": botdict["is_active"], + "api_key": botdict["api_key"], + "default_sending_stream": botdict["default_sending_stream__name"], + "default_events_register_stream": botdict["default_events_register_stream__name"], + "default_all_public_streams": botdict["default_all_public_streams"], + "owner_id": botdict["bot_owner_id"], + "avatar_url": avatar_url_from_dict(botdict), + "services": services_by_ids[botdict["id"]], + } + for botdict in result + ] diff --git a/zerver/lib/actions.py b/zerver/lib/actions.py index e13e57d3fc..5470d09e05 100644 --- a/zerver/lib/actions.py +++ b/zerver/lib/actions.py @@ -40,21 +40,20 @@ from zerver.actions.default_streams import ( do_remove_streams_from_default_stream_group, get_default_streams_for_realm, ) -from zerver.actions.invites import notify_invites_changed, revoke_invites_generated_by_user +from zerver.actions.invites import notify_invites_changed from zerver.actions.uploads import check_attachment_reference_change, do_claim_attachments from zerver.actions.user_groups import ( do_send_user_group_members_update_event, update_users_in_full_members_system_group, ) 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.addressee import Addressee from zerver.lib.alert_words import get_alert_word_automaton -from zerver.lib.avatar import avatar_url, avatar_url_from_dict -from zerver.lib.bot_config import ConfigError, get_bot_config, get_bot_configs, set_bot_config +from zerver.lib.avatar import avatar_url from zerver.lib.bulk_create import create_users from zerver.lib.cache import ( - bot_dict_fields, cache_delete, cache_delete_many, cache_set, @@ -168,7 +167,6 @@ from zerver.lib.users import ( check_bot_name_available, check_full_name, format_user_row, - get_active_bots_owned_by_user, get_api_key, user_profile_to_user_row, ) @@ -195,7 +193,6 @@ from zerver.models import ( ScheduledEmail, ScheduledMessage, ScheduledMessageNotificationEmail, - Service, Stream, Subscription, UserGroup, @@ -206,10 +203,7 @@ from zerver.models import ( active_non_guest_user_ids, active_user_ids, bot_owner_user_ids, - get_bot_dicts_in_realm, - get_bot_services, get_client, - get_fake_email_domain, get_huddle_user_ids, get_realm, get_realm_domains, @@ -217,7 +211,6 @@ from zerver.models import ( get_stream_by_id_in_realm, get_system_bot, get_user_by_delivery_email, - get_user_profile_by_id, is_cross_realm_bot_email, query_for_ids, ) @@ -1137,141 +1130,6 @@ def do_scrub_realm(realm: Realm, *, acting_user: Optional[UserProfile]) -> None: ) -def do_delete_user(user_profile: UserProfile) -> None: - if user_profile.realm.is_zephyr_mirror_realm: - raise AssertionError("Deleting zephyr mirror users is not supported") - - do_deactivate_user(user_profile, acting_user=None) - - subscribed_huddle_recipient_ids = set( - Subscription.objects.filter( - user_profile=user_profile, recipient__type=Recipient.HUDDLE - ).values_list("recipient_id", flat=True) - ) - user_id = user_profile.id - realm = user_profile.realm - date_joined = user_profile.date_joined - personal_recipient = user_profile.recipient - - with transaction.atomic(): - user_profile.delete() - # Recipient objects don't get deleted through CASCADE, so we need to handle - # the user's personal recipient manually. This will also delete all Messages pointing - # to this recipient (all private messages sent to the user). - assert personal_recipient is not None - personal_recipient.delete() - replacement_user = create_user( - force_id=user_id, - email=f"deleteduser{user_id}@{get_fake_email_domain(realm)}", - password=None, - realm=realm, - full_name=f"Deleted User {user_id}", - active=False, - is_mirror_dummy=True, - force_date_joined=date_joined, - ) - subs_to_recreate = [ - Subscription( - user_profile=replacement_user, - recipient=recipient, - is_user_active=replacement_user.is_active, - ) - for recipient in Recipient.objects.filter(id__in=subscribed_huddle_recipient_ids) - ] - Subscription.objects.bulk_create(subs_to_recreate) - - RealmAuditLog.objects.create( - realm=replacement_user.realm, - modified_user=replacement_user, - acting_user=None, - event_type=RealmAuditLog.USER_DELETED, - event_time=timezone_now(), - ) - - -def change_user_is_active(user_profile: UserProfile, value: bool) -> None: - """ - Helper function for changing the .is_active field. Not meant as a standalone function - in production code as properly activating/deactivating users requires more steps. - This changes the is_active value and saves it, while ensuring - Subscription.is_user_active values are updated in the same db transaction. - """ - with transaction.atomic(savepoint=False): - user_profile.is_active = value - user_profile.save(update_fields=["is_active"]) - Subscription.objects.filter(user_profile=user_profile).update(is_user_active=value) - - -def do_deactivate_user( - user_profile: UserProfile, _cascade: bool = True, *, acting_user: Optional[UserProfile] -) -> None: - if not user_profile.is_active: - return - - if _cascade: - # We need to deactivate bots before the target user, to ensure - # that a failure partway through this function cannot result - # in only the user being deactivated. - bot_profiles = get_active_bots_owned_by_user(user_profile) - for profile in bot_profiles: - do_deactivate_user(profile, _cascade=False, acting_user=acting_user) - - with transaction.atomic(): - if user_profile.realm.is_zephyr_mirror_realm: # nocoverage - # For zephyr mirror users, we need to make them a mirror dummy - # again; otherwise, other users won't get the correct behavior - # when trying to send messages to this person inside Zulip. - # - # Ideally, we need to also ensure their zephyr mirroring bot - # isn't running, but that's a separate issue. - user_profile.is_mirror_dummy = True - user_profile.save(update_fields=["is_mirror_dummy"]) - - change_user_is_active(user_profile, False) - - clear_scheduled_emails(user_profile.id) - revoke_invites_generated_by_user(user_profile) - - event_time = timezone_now() - RealmAuditLog.objects.create( - realm=user_profile.realm, - modified_user=user_profile, - acting_user=acting_user, - event_type=RealmAuditLog.USER_DEACTIVATED, - 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, - increment=-1, - ) - if settings.BILLING_ENABLED: - update_license_ledger_if_needed(user_profile.realm, event_time) - - delete_user_sessions(user_profile) - event = dict( - type="realm_user", - op="remove", - person=dict(user_id=user_profile.id, full_name=user_profile.full_name), - ) - send_event(user_profile.realm, event, active_user_ids(user_profile.realm_id)) - - if user_profile.is_bot: - event = dict( - type="realm_bot", - op="remove", - bot=dict(user_id=user_profile.id, full_name=user_profile.full_name), - ) - send_event(user_profile.realm, event, bot_owner_user_ids(user_profile)) - - @transaction.atomic(savepoint=False) def do_deactivate_stream( stream: Stream, log: bool = True, *, acting_user: Optional[UserProfile] @@ -4332,70 +4190,6 @@ def do_change_default_all_public_streams( ) -@transaction.atomic(durable=True) -def do_change_user_role( - user_profile: UserProfile, value: int, *, acting_user: Optional[UserProfile] -) -> None: - old_value = user_profile.role - old_system_group = get_system_user_group_for_user(user_profile) - - user_profile.role = value - user_profile.save(update_fields=["role"]) - RealmAuditLog.objects.create( - realm=user_profile.realm, - modified_user=user_profile, - acting_user=acting_user, - event_type=RealmAuditLog.USER_ROLE_CHANGED, - event_time=timezone_now(), - extra_data=orjson.dumps( - { - RealmAuditLog.OLD_VALUE: old_value, - RealmAuditLog.NEW_VALUE: value, - RealmAuditLog.ROLE_COUNT: realm_user_count_by_role(user_profile.realm), - } - ).decode(), - ) - event = dict( - type="realm_user", op="update", person=dict(user_id=user_profile.id, role=user_profile.role) - ) - transaction.on_commit( - lambda: send_event(user_profile.realm, event, active_user_ids(user_profile.realm_id)) - ) - - UserGroupMembership.objects.filter( - user_profile=user_profile, user_group=old_system_group - ).delete() - - system_group = get_system_user_group_for_user(user_profile) - UserGroupMembership.objects.create(user_profile=user_profile, user_group=system_group) - - do_send_user_group_members_update_event("remove_members", old_system_group, [user_profile.id]) - - do_send_user_group_members_update_event("add_members", system_group, [user_profile.id]) - - if UserProfile.ROLE_MEMBER in [old_value, value]: - update_users_in_full_members_system_group(user_profile.realm, [user_profile.id]) - - -def do_make_user_billing_admin(user_profile: UserProfile) -> None: - user_profile.is_billing_admin = True - user_profile.save(update_fields=["is_billing_admin"]) - event = dict( - type="realm_user", op="update", person=dict(user_id=user_profile.id, is_billing_admin=True) - ) - send_event(user_profile.realm, event, active_user_ids(user_profile.realm_id)) - - -def do_change_can_forge_sender(user_profile: UserProfile, value: bool) -> None: - user_profile.can_forge_sender = value - user_profile.save(update_fields=["can_forge_sender"]) - - -def do_change_can_create_users(user_profile: UserProfile, value: bool) -> None: - user_profile.can_create_users = value - user_profile.save(update_fields=["can_create_users"]) - - def send_change_stream_permission_notification( stream: Stream, *, @@ -6477,148 +6271,6 @@ def do_remove_realm_domain( transaction.on_commit(lambda: send_event(realm, event, active_user_ids(realm.id))) -def do_update_outgoing_webhook_service( - bot_profile: UserProfile, service_interface: int, service_payload_url: str -) -> None: - # TODO: First service is chosen because currently one bot can only have one service. - # Update this once multiple services are supported. - service = get_bot_services(bot_profile.id)[0] - service.base_url = service_payload_url - service.interface = service_interface - service.save() - send_event( - bot_profile.realm, - dict( - type="realm_bot", - op="update", - bot=dict( - user_id=bot_profile.id, - services=[ - dict( - base_url=service.base_url, interface=service.interface, token=service.token - ) - ], - ), - ), - bot_owner_user_ids(bot_profile), - ) - - -def do_update_bot_config_data(bot_profile: UserProfile, config_data: Dict[str, str]) -> None: - for key, value in config_data.items(): - set_bot_config(bot_profile, key, value) - updated_config_data = get_bot_config(bot_profile) - send_event( - bot_profile.realm, - dict( - type="realm_bot", - op="update", - bot=dict( - user_id=bot_profile.id, - services=[dict(config_data=updated_config_data)], - ), - ), - bot_owner_user_ids(bot_profile), - ) - - -def get_service_dicts_for_bot(user_profile_id: int) -> List[Dict[str, Any]]: - user_profile = get_user_profile_by_id(user_profile_id) - services = get_bot_services(user_profile_id) - service_dicts: List[Dict[str, Any]] = [] - if user_profile.bot_type == UserProfile.OUTGOING_WEBHOOK_BOT: - service_dicts = [ - { - "base_url": service.base_url, - "interface": service.interface, - "token": service.token, - } - for service in services - ] - elif user_profile.bot_type == UserProfile.EMBEDDED_BOT: - try: - service_dicts = [ - { - "config_data": get_bot_config(user_profile), - "service_name": services[0].name, - } - ] - # A ConfigError just means that there are no config entries for user_profile. - except ConfigError: - pass - return service_dicts - - -def get_service_dicts_for_bots( - bot_dicts: List[Dict[str, Any]], realm: Realm -) -> Dict[int, List[Dict[str, Any]]]: - bot_profile_ids = [bot_dict["id"] for bot_dict in bot_dicts] - bot_services_by_uid: Dict[int, List[Service]] = defaultdict(list) - for service in Service.objects.filter(user_profile_id__in=bot_profile_ids): - bot_services_by_uid[service.user_profile_id].append(service) - - embedded_bot_ids = [ - bot_dict["id"] for bot_dict in bot_dicts if bot_dict["bot_type"] == UserProfile.EMBEDDED_BOT - ] - embedded_bot_configs = get_bot_configs(embedded_bot_ids) - - service_dicts_by_uid: Dict[int, List[Dict[str, Any]]] = {} - for bot_dict in bot_dicts: - bot_profile_id = bot_dict["id"] - bot_type = bot_dict["bot_type"] - services = bot_services_by_uid[bot_profile_id] - service_dicts: List[Dict[str, Any]] = [] - if bot_type == UserProfile.OUTGOING_WEBHOOK_BOT: - service_dicts = [ - { - "base_url": service.base_url, - "interface": service.interface, - "token": service.token, - } - for service in services - ] - elif bot_type == UserProfile.EMBEDDED_BOT: - if bot_profile_id in embedded_bot_configs.keys(): - bot_config = embedded_bot_configs[bot_profile_id] - service_dicts = [ - { - "config_data": bot_config, - "service_name": services[0].name, - } - ] - service_dicts_by_uid[bot_profile_id] = service_dicts - return service_dicts_by_uid - - -def get_owned_bot_dicts( - user_profile: UserProfile, include_all_realm_bots_if_admin: bool = True -) -> List[Dict[str, Any]]: - if user_profile.is_realm_admin and include_all_realm_bots_if_admin: - result = get_bot_dicts_in_realm(user_profile.realm) - else: - result = UserProfile.objects.filter( - realm=user_profile.realm, is_bot=True, bot_owner=user_profile - ).values(*bot_dict_fields) - services_by_ids = get_service_dicts_for_bots(result, user_profile.realm) - return [ - { - "email": botdict["email"], - "user_id": botdict["id"], - "full_name": botdict["full_name"], - "bot_type": botdict["bot_type"], - "is_active": botdict["is_active"], - "api_key": botdict["api_key"], - "default_sending_stream": botdict["default_sending_stream__name"], - "default_events_register_stream": botdict["default_events_register_stream__name"], - "default_all_public_streams": botdict["default_all_public_streams"], - "owner_id": botdict["bot_owner_id"], - "avatar_url": avatar_url_from_dict(botdict), - "services": services_by_ids[botdict["id"]], - } - for botdict in result - ] - - def do_send_realm_reactivation_email(realm: Realm, *, acting_user: Optional[UserProfile]) -> None: url = create_confirmation_link(realm, Confirmation.REALM_REACTIVATION) RealmAuditLog.objects.create( diff --git a/zerver/lib/events.py b/zerver/lib/events.py index b2ae2b545a..b26c7cff70 100644 --- a/zerver/lib/events.py +++ b/zerver/lib/events.py @@ -13,7 +13,7 @@ from zerver.actions.default_streams import ( get_default_streams_for_realm, streams_to_dicts_sorted, ) -from zerver.lib.actions import get_owned_bot_dicts +from zerver.actions.users import get_owned_bot_dicts from zerver.lib.alert_words import user_alert_words from zerver.lib.avatar import avatar_url from zerver.lib.bot_config import load_bot_config_template diff --git a/zerver/lib/scim.py b/zerver/lib/scim.py index 6ac103133a..c19f438ed9 100644 --- a/zerver/lib/scim.py +++ b/zerver/lib/scim.py @@ -9,11 +9,11 @@ from django.http import HttpRequest from django_scim.adapters import SCIMUser from scim2_filter_parser.attr_paths import AttrPath +from zerver.actions.users import do_deactivate_user from zerver.lib.actions import ( check_change_full_name, do_change_user_delivery_email, do_create_user, - do_deactivate_user, do_reactivate_user, ) from zerver.lib.email_validation import email_allowed_for_realm, validate_email_not_already_in_realm diff --git a/zerver/lib/server_initialization.py b/zerver/lib/server_initialization.py index 93c33e9b0f..946cf82985 100644 --- a/zerver/lib/server_initialization.py +++ b/zerver/lib/server_initialization.py @@ -18,7 +18,7 @@ def server_initialized() -> bool: def create_internal_realm() -> None: - from zerver.lib.actions import do_change_can_forge_sender + from zerver.actions.users import do_change_can_forge_sender realm = Realm.objects.create(string_id=settings.SYSTEM_BOT_REALM, name="System bot realm") RealmAuditLog.objects.create( diff --git a/zerver/management/commands/change_user_role.py b/zerver/management/commands/change_user_role.py index eb08312d1f..6db2acd79f 100644 --- a/zerver/management/commands/change_user_role.py +++ b/zerver/management/commands/change_user_role.py @@ -3,7 +3,7 @@ from typing import Any from django.core.management.base import CommandError -from zerver.lib.actions import ( +from zerver.actions.users import ( do_change_can_create_users, do_change_can_forge_sender, do_change_user_role, diff --git a/zerver/management/commands/deactivate_user.py b/zerver/management/commands/deactivate_user.py index ab83e0d954..a398e00b07 100644 --- a/zerver/management/commands/deactivate_user.py +++ b/zerver/management/commands/deactivate_user.py @@ -3,7 +3,7 @@ from typing import Any from django.core.management.base import CommandError -from zerver.lib.actions import do_deactivate_user +from zerver.actions.users import do_deactivate_user from zerver.lib.management import ZulipBaseCommand from zerver.lib.sessions import user_sessions from zerver.lib.users import get_active_bots_owned_by_user diff --git a/zerver/management/commands/delete_user.py b/zerver/management/commands/delete_user.py index fec47cb5aa..e2c4a779bc 100644 --- a/zerver/management/commands/delete_user.py +++ b/zerver/management/commands/delete_user.py @@ -3,7 +3,7 @@ from typing import Any from django.core.management.base import CommandError -from zerver.lib.actions import do_delete_user +from zerver.actions.users import do_delete_user from zerver.lib.management import ZulipBaseCommand from zerver.lib.users import get_active_bots_owned_by_user diff --git a/zerver/tests/test_audit_log.py b/zerver/tests/test_audit_log.py index a3a62069b8..c9734a6b8e 100644 --- a/zerver/tests/test_audit_log.py +++ b/zerver/tests/test_audit_log.py @@ -8,6 +8,7 @@ from django.utils.timezone import now as timezone_now from analytics.models import StreamCount 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.users import do_change_user_role, do_deactivate_user from zerver.lib.actions import ( bulk_add_subscriptions, bulk_remove_subscriptions, @@ -23,12 +24,10 @@ from zerver.lib.actions import ( do_change_subscription_property, do_change_tos_version, do_change_user_delivery_email, - do_change_user_role, do_change_user_setting, do_create_user, do_deactivate_realm, do_deactivate_stream, - do_deactivate_user, do_reactivate_realm, do_reactivate_user, do_regenerate_api_key, diff --git a/zerver/tests/test_auth_backends.py b/zerver/tests/test_auth_backends.py index 9855445f2f..0fcf389517 100644 --- a/zerver/tests/test_auth_backends.py +++ b/zerver/tests/test_auth_backends.py @@ -41,13 +41,12 @@ from social_django.strategy import DjangoStrategy from confirmation.models import Confirmation, create_confirmation_link from zerver.actions.invites import do_invite_users +from zerver.actions.users import change_user_is_active, do_deactivate_user from zerver.lib.actions import ( - change_user_is_active, do_change_password, do_create_realm, do_create_user, do_deactivate_realm, - do_deactivate_user, do_reactivate_realm, do_reactivate_user, do_set_realm_property, diff --git a/zerver/tests/test_bots.py b/zerver/tests/test_bots.py index 09daaca700..6ef71895b9 100644 --- a/zerver/tests/test_bots.py +++ b/zerver/tests/test_bots.py @@ -8,12 +8,8 @@ from django.core import mail from django.test import override_settings from zulip_bots.custom_exceptions import ConfigValidationError -from zerver.lib.actions import ( - do_change_can_create_users, - do_change_stream_permission, - do_deactivate_user, - do_set_realm_property, -) +from zerver.actions.users import do_change_can_create_users, do_deactivate_user +from zerver.lib.actions import do_change_stream_permission, do_set_realm_property from zerver.lib.bot_config import ConfigError, get_bot_config from zerver.lib.bot_lib import get_bot_handler from zerver.lib.integrations import EMBEDDED_BOTS, WebhookIntegration diff --git a/zerver/tests/test_decorators.py b/zerver/tests/test_decorators.py index e4abea91b9..d98ee600d8 100644 --- a/zerver/tests/test_decorators.py +++ b/zerver/tests/test_decorators.py @@ -14,6 +14,7 @@ from django.core.exceptions import ValidationError from django.http import HttpRequest, HttpResponse from django.utils.timezone import now as timezone_now +from zerver.actions.users import change_user_is_active, do_deactivate_user from zerver.decorator import ( authenticate_notify, authenticated_json_view, @@ -29,10 +30,8 @@ from zerver.decorator import ( ) from zerver.forms import OurAuthenticationForm from zerver.lib.actions import ( - change_user_is_active, do_create_realm, do_deactivate_realm, - do_deactivate_user, do_reactivate_realm, do_reactivate_user, do_set_realm_property, diff --git a/zerver/tests/test_email_change.py b/zerver/tests/test_email_change.py index 4eb16c3a4c..71032028b8 100644 --- a/zerver/tests/test_email_change.py +++ b/zerver/tests/test_email_change.py @@ -11,9 +11,9 @@ from confirmation.models import ( create_confirmation_link, generate_key, ) +from zerver.actions.users import do_deactivate_user from zerver.lib.actions import ( do_deactivate_realm, - do_deactivate_user, do_set_realm_property, do_start_email_change_process, ) diff --git a/zerver/tests/test_email_mirror.py b/zerver/tests/test_email_mirror.py index d02ec3fd2d..20ec2b6e20 100644 --- a/zerver/tests/test_email_mirror.py +++ b/zerver/tests/test_email_mirror.py @@ -11,7 +11,8 @@ import orjson from django.conf import settings from django.http import HttpResponse -from zerver.lib.actions import do_change_stream_post_policy, do_deactivate_realm, do_deactivate_user +from zerver.actions.users import do_deactivate_user +from zerver.lib.actions import do_change_stream_post_policy, do_deactivate_realm from zerver.lib.email_mirror import ( create_missed_message_address, filter_footer, diff --git a/zerver/tests/test_email_notifications.py b/zerver/tests/test_email_notifications.py index 202d784a73..6d44c49622 100644 --- a/zerver/tests/test_email_notifications.py +++ b/zerver/tests/test_email_notifications.py @@ -15,7 +15,8 @@ from django.test import override_settings from django.utils.timezone import now as timezone_now from django_auth_ldap.config import LDAPSearch -from zerver.lib.actions import do_change_user_role, do_change_user_setting +from zerver.actions.users import do_change_user_role +from zerver.lib.actions import do_change_user_setting from zerver.lib.email_notifications import ( enqueue_welcome_emails, fix_emojis, diff --git a/zerver/tests/test_event_system.py b/zerver/tests/test_event_system.py index 479aeaa5d5..8f96ed92f7 100644 --- a/zerver/tests/test_event_system.py +++ b/zerver/tests/test_event_system.py @@ -9,7 +9,8 @@ from django.utils.timezone import now as timezone_now from version import API_FEATURE_LEVEL, ZULIP_MERGE_BASE, ZULIP_VERSION from zerver.actions.presence import do_update_user_presence -from zerver.lib.actions import check_send_message, do_change_user_role, do_set_realm_property +from zerver.actions.users import do_change_user_role +from zerver.lib.actions import check_send_message, do_set_realm_property from zerver.lib.event_schema import check_restart_event from zerver.lib.events import fetch_initial_state_data from zerver.lib.exceptions import AccessDeniedError diff --git a/zerver/tests/test_events.py b/zerver/tests/test_events.py index d7339f4bb8..48b4ad1ab6 100644 --- a/zerver/tests/test_events.py +++ b/zerver/tests/test_events.py @@ -59,6 +59,12 @@ from zerver.actions.user_groups import ( remove_members_from_user_group, ) from zerver.actions.user_topics import do_mute_topic, do_unmute_topic +from zerver.actions.users import ( + do_change_user_role, + do_deactivate_user, + do_make_user_billing_admin, + do_update_outgoing_webhook_service, +) from zerver.actions.video_calls import do_set_zoom_token from zerver.lib.actions import ( bulk_add_subscriptions, @@ -79,14 +85,11 @@ from zerver.lib.actions import ( do_change_stream_post_policy, do_change_subscription_property, do_change_user_delivery_email, - do_change_user_role, do_change_user_setting, do_create_user, do_deactivate_realm, do_deactivate_stream, - do_deactivate_user, do_delete_messages, - do_make_user_billing_admin, do_mute_user, do_reactivate_user, do_regenerate_api_key, @@ -103,7 +106,6 @@ from zerver.lib.actions import ( do_update_embedded_data, do_update_message, do_update_message_flags, - do_update_outgoing_webhook_service, ) from zerver.lib.drafts import do_create_drafts, do_delete_draft, do_edit_draft from zerver.lib.event_schema import ( diff --git a/zerver/tests/test_example.py b/zerver/tests/test_example.py index 28eaf8becf..8f028b4729 100644 --- a/zerver/tests/test_example.py +++ b/zerver/tests/test_example.py @@ -5,7 +5,7 @@ from unittest import mock import orjson from django.utils.timezone import now as timezone_now -from zerver.lib.actions import do_change_can_create_users, do_change_user_role +from zerver.actions.users import do_change_can_create_users, do_change_user_role from zerver.lib.exceptions import JsonableError from zerver.lib.streams import access_stream_for_send_message from zerver.lib.test_classes import ZulipTestCase diff --git a/zerver/tests/test_home.py b/zerver/tests/test_home.py index 141ff64e1f..b50c4cc8ce 100644 --- a/zerver/tests/test_home.py +++ b/zerver/tests/test_home.py @@ -13,7 +13,8 @@ from django.test import override_settings from django.utils.timezone import now as timezone_now from corporate.models import Customer, CustomerPlan -from zerver.lib.actions import change_user_is_active, do_change_realm_plan_type, do_create_user +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.compatibility import LAST_SERVER_UPGRADE_TIME, is_outdated_server from zerver.lib.home import ( get_billing_info, diff --git a/zerver/tests/test_import_export.py b/zerver/tests/test_import_export.py index 8725e8d23d..32ed9f90d7 100644 --- a/zerver/tests/test_import_export.py +++ b/zerver/tests/test_import_export.py @@ -21,13 +21,13 @@ from zerver.actions.realm_icon import do_change_icon_source from zerver.actions.realm_logo import do_change_logo_source from zerver.actions.user_activity import do_update_user_activity, do_update_user_activity_interval from zerver.actions.user_topics import do_mute_topic +from zerver.actions.users import do_deactivate_user from zerver.lib import upload from zerver.lib.actions import ( check_add_reaction, do_add_reaction, do_change_realm_plan_type, do_create_user, - do_deactivate_user, do_mute_user, ) from zerver.lib.avatar_hash import user_avatar_path diff --git a/zerver/tests/test_markdown.py b/zerver/tests/test_markdown.py index 0d9f2ab34b..5f745883e3 100644 --- a/zerver/tests/test_markdown.py +++ b/zerver/tests/test_markdown.py @@ -12,12 +12,8 @@ from markdown import Markdown from zerver.actions.alert_words import do_add_alert_words from zerver.actions.realm_emoji import do_remove_realm_emoji -from zerver.lib.actions import ( - change_user_is_active, - do_change_user_setting, - do_create_realm, - do_set_realm_property, -) +from zerver.actions.users import change_user_is_active +from zerver.lib.actions import do_change_user_setting, do_create_realm, do_set_realm_property from zerver.lib.alert_words import get_alert_word_automaton from zerver.lib.camo import get_camo_url from zerver.lib.create_user import create_user diff --git a/zerver/tests/test_message_edit.py b/zerver/tests/test_message_edit.py index 41353dd3d7..dc8c2ca247 100644 --- a/zerver/tests/test_message_edit.py +++ b/zerver/tests/test_message_edit.py @@ -8,12 +8,12 @@ from django.db import IntegrityError from django.http import HttpResponse from django.utils.timezone import now as timezone_now +from zerver.actions.users import do_change_user_role from zerver.lib.actions import ( check_update_message, do_add_reaction, do_change_realm_plan_type, do_change_stream_post_policy, - do_change_user_role, do_deactivate_stream, do_delete_messages, do_set_realm_property, diff --git a/zerver/tests/test_message_fetch.py b/zerver/tests/test_message_fetch.py index f311b2d9ad..8269d96fc3 100644 --- a/zerver/tests/test_message_fetch.py +++ b/zerver/tests/test_message_fetch.py @@ -14,7 +14,8 @@ from sqlalchemy.types import Integer from analytics.lib.counts import COUNT_STATS from analytics.models import RealmCount from zerver.actions.uploads import do_claim_attachments -from zerver.lib.actions import do_deactivate_user, do_set_realm_property, do_update_message +from zerver.actions.users import do_deactivate_user +from zerver.lib.actions import do_set_realm_property, do_update_message from zerver.lib.avatar import avatar_url from zerver.lib.exceptions import JsonableError from zerver.lib.mention import MentionBackend, MentionData diff --git a/zerver/tests/test_message_send.py b/zerver/tests/test_message_send.py index 7b3c3ab4be..5d561e29af 100644 --- a/zerver/tests/test_message_send.py +++ b/zerver/tests/test_message_send.py @@ -10,16 +10,15 @@ from django.http import HttpResponse from django.test import override_settings from django.utils.timezone import now as timezone_now +from zerver.actions.users import do_change_can_forge_sender, do_deactivate_user from zerver.lib.actions import ( build_message_send_dict, check_message, check_send_stream_message, do_add_realm_domain, - do_change_can_forge_sender, do_change_stream_post_policy, do_create_realm, do_create_user, - do_deactivate_user, do_send_messages, do_set_realm_property, extract_private_recipients, diff --git a/zerver/tests/test_muting_users.py b/zerver/tests/test_muting_users.py index c06f740348..5b70efde4a 100644 --- a/zerver/tests/test_muting_users.py +++ b/zerver/tests/test_muting_users.py @@ -3,7 +3,7 @@ from unittest import mock import orjson -from zerver.lib.actions import do_deactivate_user +from zerver.actions.users import do_deactivate_user from zerver.lib.cache import cache_get, get_muting_users_cache_key from zerver.lib.test_classes import ZulipTestCase from zerver.lib.timestamp import datetime_to_timestamp diff --git a/zerver/tests/test_presence.py b/zerver/tests/test_presence.py index 431c9cd57f..95d1be5ff6 100644 --- a/zerver/tests/test_presence.py +++ b/zerver/tests/test_presence.py @@ -5,7 +5,7 @@ from unittest import mock from django.utils.timezone import now as timezone_now -from zerver.lib.actions import do_deactivate_user +from zerver.actions.users import do_deactivate_user from zerver.lib.presence import get_status_dict_by_realm from zerver.lib.test_classes import ZulipTestCase from zerver.lib.test_helpers import make_client, reset_emails_in_zulip_realm diff --git a/zerver/tests/test_realm_domains.py b/zerver/tests/test_realm_domains.py index 8ae68d2436..cd932937d4 100644 --- a/zerver/tests/test_realm_domains.py +++ b/zerver/tests/test_realm_domains.py @@ -2,9 +2,9 @@ import orjson from django.core.exceptions import ValidationError from django.db.utils import IntegrityError +from zerver.actions.users import do_change_user_role from zerver.lib.actions import ( do_change_realm_domain, - do_change_user_role, do_create_realm, do_remove_realm_domain, do_set_realm_property, diff --git a/zerver/tests/test_realm_emoji.py b/zerver/tests/test_realm_emoji.py index 90bc5f1d83..ff832129b7 100644 --- a/zerver/tests/test_realm_emoji.py +++ b/zerver/tests/test_realm_emoji.py @@ -1,12 +1,8 @@ from unittest import mock from zerver.actions.realm_emoji import check_add_realm_emoji -from zerver.lib.actions import ( - do_change_user_role, - do_create_realm, - do_create_user, - do_set_realm_property, -) +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.exceptions import JsonableError from zerver.lib.test_classes import ZulipTestCase from zerver.lib.test_helpers import get_test_image_file diff --git a/zerver/tests/test_sessions.py b/zerver/tests/test_sessions.py index 95497630f2..9a2fb626fa 100644 --- a/zerver/tests/test_sessions.py +++ b/zerver/tests/test_sessions.py @@ -4,7 +4,7 @@ from unittest import mock from django.utils.timezone import now as timezone_now -from zerver.lib.actions import change_user_is_active +from zerver.actions.users import change_user_is_active from zerver.lib.sessions import ( delete_all_deactivated_user_sessions, delete_all_user_sessions, diff --git a/zerver/tests/test_signup.py b/zerver/tests/test_signup.py index a0c2001eea..162dbb79fe 100644 --- a/zerver/tests/test_signup.py +++ b/zerver/tests/test_signup.py @@ -35,19 +35,17 @@ from zerver.actions.invites import ( do_get_invites_controlled_by_user, do_invite_users, ) +from zerver.actions.users import change_user_is_active, do_change_user_role, do_deactivate_user from zerver.context_processors import common_context from zerver.decorator import do_two_factor_login from zerver.forms import HomepageForm, check_subdomain_available from zerver.lib.actions import ( add_new_user_history, - change_user_is_active, do_change_full_name, do_change_realm_subdomain, - do_change_user_role, do_create_realm, do_create_user, do_deactivate_realm, - do_deactivate_user, do_set_realm_property, do_set_realm_user_default_setting, process_new_human_user, diff --git a/zerver/tests/test_subs.py b/zerver/tests/test_subs.py index b44c5da753..3dd73c1d97 100644 --- a/zerver/tests/test_subs.py +++ b/zerver/tests/test_subs.py @@ -23,16 +23,15 @@ from zerver.actions.default_streams import ( get_default_streams_for_realm, lookup_default_stream_groups, ) +from zerver.actions.users import do_change_user_role, do_deactivate_user from zerver.lib.actions import ( bulk_add_subscriptions, bulk_remove_subscriptions, do_change_realm_plan_type, do_change_stream_post_policy, do_change_subscription_property, - do_change_user_role, do_create_realm, do_deactivate_stream, - do_deactivate_user, do_set_realm_property, get_topic_messages, ) diff --git a/zerver/tests/test_users.py b/zerver/tests/test_users.py index d4db667f70..684d94f405 100644 --- a/zerver/tests/test_users.py +++ b/zerver/tests/test_users.py @@ -13,13 +13,15 @@ from django.utils.timezone import now as timezone_now from confirmation.models import Confirmation from zerver.actions.invites import do_create_multiuse_invite_link, do_invite_users -from zerver.lib.actions import ( +from zerver.actions.users import ( change_user_is_active, do_change_can_create_users, do_change_user_role, - do_create_user, do_deactivate_user, do_delete_user, +) +from zerver.lib.actions import ( + do_create_user, do_mute_user, do_reactivate_user, do_set_realm_property, diff --git a/zerver/views/development/email_log.py b/zerver/views/development/email_log.py index 20f5f31ca4..213b938f0d 100755 --- a/zerver/views/development/email_log.py +++ b/zerver/views/development/email_log.py @@ -9,11 +9,8 @@ from django.shortcuts import redirect, render from django.views.decorators.http import require_safe from confirmation.models import Confirmation, confirmation_url -from zerver.lib.actions import ( - change_user_is_active, - do_change_user_delivery_email, - do_send_realm_reactivation_email, -) +from zerver.actions.users import change_user_is_active +from zerver.lib.actions import do_change_user_delivery_email, do_send_realm_reactivation_email from zerver.lib.email_notifications import enqueue_welcome_emails from zerver.lib.response import json_success from zerver.models import Realm, get_realm, get_realm_stream, get_user_by_delivery_email diff --git a/zerver/views/users.py b/zerver/views/users.py index abbb4733f5..c9d8cc64b7 100644 --- a/zerver/views/users.py +++ b/zerver/views/users.py @@ -10,6 +10,12 @@ from zerver.actions.custom_profile_fields import ( check_remove_custom_profile_field_value, do_update_user_custom_profile_data_if_changed, ) +from zerver.actions.users import ( + do_change_user_role, + do_deactivate_user, + do_update_bot_config_data, + do_update_outgoing_webhook_service, +) from zerver.context_processors import get_valid_realm_from_request from zerver.decorator import require_member_or_admin, require_realm_admin from zerver.forms import PASSWORD_TOO_WEAK_ERROR, CreateUserForm @@ -21,13 +27,9 @@ from zerver.lib.actions import ( do_change_default_all_public_streams, do_change_default_events_register_stream, do_change_default_sending_stream, - do_change_user_role, do_create_user, - do_deactivate_user, do_reactivate_user, do_regenerate_api_key, - do_update_bot_config_data, - do_update_outgoing_webhook_service, notify_created_bot, ) from zerver.lib.avatar import avatar_url, get_gravatar_url diff --git a/zilencer/management/commands/populate_db.py b/zilencer/management/commands/populate_db.py index c6c53abecd..d98eaaad6b 100644 --- a/zilencer/management/commands/populate_db.py +++ b/zilencer/management/commands/populate_db.py @@ -24,12 +24,8 @@ from zerver.actions.custom_profile_fields import ( try_add_realm_default_custom_profile_field, ) from zerver.actions.realm_emoji import check_add_realm_emoji -from zerver.lib.actions import ( - build_message_send_dict, - do_change_user_role, - do_create_realm, - do_send_messages, -) +from zerver.actions.users import do_change_user_role +from zerver.lib.actions import build_message_send_dict, do_create_realm, do_send_messages from zerver.lib.bulk_create import bulk_create_streams from zerver.lib.cache import cache_set from zerver.lib.generate_test_data import create_test_data, generate_topics diff --git a/zproject/backends.py b/zproject/backends.py index f5e6b35073..b96921b058 100644 --- a/zproject/backends.py +++ b/zproject/backends.py @@ -59,13 +59,9 @@ from typing_extensions import TypedDict from zxcvbn import zxcvbn from zerver.actions.custom_profile_fields import do_update_user_custom_profile_data_if_changed +from zerver.actions.users import do_deactivate_user from zerver.decorator import client_is_exempt_from_rate_limiting -from zerver.lib.actions import ( - do_create_user, - do_deactivate_user, - do_reactivate_user, - do_regenerate_api_key, -) +from zerver.lib.actions import do_create_user, do_reactivate_user, do_regenerate_api_key from zerver.lib.avatar import avatar_url, is_avatar_new from zerver.lib.avatar_hash import user_avatar_content_hash from zerver.lib.dev_ldap_directory import init_fakeldap