slack_import: Ask importer for default email address visibility.

Fixes #34982
This commit is contained in:
Aman Agrawal
2025-10-13 12:22:48 +05:30
committed by Tim Abbott
parent 4bd9bb1995
commit f86654ba5f
7 changed files with 117 additions and 6 deletions

View File

@@ -1,5 +1,5 @@
<p id="new-user-email-address-visibility" class="registration-form-hint"> <p id="new-user-email-address-visibility" class="registration-form-hint">
<input type="hidden" name="email_address_visibility" id="email_address_visibility"/> <input type="hidden" name="email_address_visibility" value="{{ default_email_address_visibility }}" id="email_address_visibility"/>
<span class="current-selected-option"> <span class="current-selected-option">
{% if default_email_address_visibility == email_address_visibility_admins_only %} {% if default_email_address_visibility == email_address_visibility_admins_only %}
{% trans %}Administrators of this Zulip organization will be able to see this email address. {% trans %}Administrators of this Zulip organization will be able to see this email address.

View File

@@ -82,6 +82,22 @@
<label for="uploaded-file-info">{{ _("Uploaded export file") }}</label> <label for="uploaded-file-info">{{ _("Uploaded export file") }}</label>
<div class="not-editable-realm-field" id="slack-import-uploaded-file-name">{{ uploaded_import_file_name }}</div> <div class="not-editable-realm-field" id="slack-import-uploaded-file-name">{{ uploaded_import_file_name }}</div>
</div> </div>
<div class="input-group input-box" id="email-address-visibility-select-wrapper">
<label for="email-address-visibility-select">
{{ _("By default, who will be allowed to see other users' email addresses?") }}
<br />
<span id="email-address-visibility-help-text">
{% trans %}
Users can <a href="https://zulip.com/help/configure-email-visibility" target="_blank">change</a> their email visibility configuration when they log in.
{% endtrans %}
</span>
</label>
<select id="email-address-visibility-select" name="email_address_visibility" class="required">
{% for value, label in email_address_visibility_options %}
<option value="{{ value }}" {% if value == email_address_visibility_default %}selected{% endif %}>{{ _(label) }}</option>
{% endfor %}
</select>
</div>
<div class="input-box"> <div class="input-box">
<button type="submit" class="register-button"{% if invalid_file_error_message %} disabled{% endif %}> <button type="submit" class="register-button"{% if invalid_file_error_message %} disabled{% endif %}>
{{ _("Start import") }} {{ _("Start import") }}

View File

@@ -1581,3 +1581,18 @@ button#register_auth_button_gitlab {
.self-hosting-login-help-text { .self-hosting-login-help-text {
margin-top: 10px; margin-top: 10px;
} }
#email-address-visibility-select {
margin-top: 100px;
padding-right: 10px;
white-space: nowrap;
text-overflow: ellipsis;
}
#email-address-visibility-select-wrapper label {
text-align: left;
}
#email-address-visibility-help-text {
font-weight: normal;
}

View File

@@ -6,6 +6,7 @@ from typing import Any
from django.conf import settings from django.conf import settings
from confirmation import settings as confirmation_settings from confirmation import settings as confirmation_settings
from zerver.actions.create_realm import get_email_address_visibility_default
from zerver.actions.realm_settings import do_delete_all_realm_attachments from zerver.actions.realm_settings import do_delete_all_realm_attachments
from zerver.actions.users import do_change_user_role from zerver.actions.users import do_change_user_role
from zerver.context_processors import is_realm_import_enabled from zerver.context_processors import is_realm_import_enabled
@@ -15,7 +16,7 @@ from zerver.lib.import_realm import do_import_realm
from zerver.lib.upload import save_attachment_contents from zerver.lib.upload import save_attachment_contents
from zerver.models.prereg_users import PreregistrationRealm from zerver.models.prereg_users import PreregistrationRealm
from zerver.models.realms import Realm from zerver.models.realms import Realm
from zerver.models.users import UserProfile, get_user_by_delivery_email from zerver.models.users import RealmUserDefault, UserProfile, get_user_by_delivery_email
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -51,6 +52,20 @@ def import_slack_data(event: dict[str, Any]) -> None:
realm.default_language = preregistration_realm.default_language realm.default_language = preregistration_realm.default_language
realm.save() realm.save()
realm_user_default = RealmUserDefault.objects.get(realm=realm)
realm_user_default.email_address_visibility = (
preregistration_realm.data_import_metadata.get(
"email_address_visibility",
get_email_address_visibility_default(realm.org_type),
)
)
realm_user_default.save(update_fields=["email_address_visibility"])
# Set email address visibility for all users in the realm.
UserProfile.objects.filter(realm=realm, is_bot=False).update(
email_address_visibility=realm_user_default.email_address_visibility
)
# Try finding the user who imported this realm and make them owner. # Try finding the user who imported this realm and make them owner.
try: try:
importing_user = get_user_by_delivery_email(preregistration_realm.email, realm) importing_user = get_user_by_delivery_email(preregistration_realm.email, realm)

View File

@@ -16,7 +16,8 @@ from requests.models import PreparedRequest
from confirmation import settings as confirmation_settings from confirmation import settings as confirmation_settings
from confirmation.models import Confirmation, get_object_from_key from confirmation.models import Confirmation, get_object_from_key
from zerver.actions.create_realm import do_create_realm from zerver.actions.create_realm import do_create_realm, get_email_address_visibility_default
from zerver.actions.create_user import do_create_user
from zerver.actions.data_import import import_slack_data from zerver.actions.data_import import import_slack_data
from zerver.data_import.import_util import ( from zerver.data_import.import_util import (
ZerverFieldsT, ZerverFieldsT,
@@ -2212,6 +2213,8 @@ by Pieter
prereg_realm.data_import_metadata["uploaded_import_file_name"] = "test_slack_importer.zip" prereg_realm.data_import_metadata["uploaded_import_file_name"] = "test_slack_importer.zip"
prereg_realm.save() prereg_realm.save()
# Set by the user performing the import.
importer_set_email_address_visibility = UserProfile.EMAIL_ADDRESS_VISIBILITY_NOBODY
# Check that deferred_work for import is queued. # Check that deferred_work for import is queued.
with mock.patch("zerver.views.registration.queue_json_publish_rollback_unsafe") as m: with mock.patch("zerver.views.registration.queue_json_publish_rollback_unsafe") as m:
result = self.client_post( result = self.client_post(
@@ -2219,11 +2222,16 @@ by Pieter
{ {
"key": confirmation_key, "key": confirmation_key,
"start_slack_import": "true", "start_slack_import": "true",
"email_address_visibility": importer_set_email_address_visibility,
}, },
) )
self.assert_in_success_response(["Import progress"], result) self.assert_in_success_response(["Import progress"], result)
prereg_realm.refresh_from_db() prereg_realm.refresh_from_db()
self.assertTrue(prereg_realm.data_import_metadata["is_import_work_queued"]) self.assertTrue(prereg_realm.data_import_metadata["is_import_work_queued"])
self.assertTrue(
prereg_realm.data_import_metadata["email_address_visibility"],
importer_set_email_address_visibility,
)
m.assert_called_once_with( m.assert_called_once_with(
"deferred_work", "deferred_work",
@@ -2242,6 +2250,26 @@ by Pieter
string_id=prereg_realm.string_id, string_id=prereg_realm.string_id,
name=prereg_realm.name, name=prereg_realm.name,
) )
test_user = do_create_user("email1", "password", realm, "full_name", acting_user=None)
test_bot_user = do_create_user(
"bot_email",
"password",
realm,
"bot_full_name",
bot_type=UserProfile.DEFAULT_BOT,
acting_user=None,
)
self.assertEqual(
get_email_address_visibility_default(realm.org_type),
UserProfile.EMAIL_ADDRESS_VISIBILITY_ADMINS,
)
self.assertEqual(
test_user.email_address_visibility, UserProfile.EMAIL_ADDRESS_VISIBILITY_ADMINS
)
self.assertEqual(
test_bot_user.email_address_visibility, UserProfile.EMAIL_ADDRESS_VISIBILITY_EVERYONE
)
with ( with (
mock.patch( mock.patch(
"zerver.actions.data_import.save_attachment_contents" "zerver.actions.data_import.save_attachment_contents"
@@ -2271,6 +2299,18 @@ by Pieter
prereg_realm.refresh_from_db() prereg_realm.refresh_from_db()
self.assertTrue(prereg_realm.data_import_metadata["need_select_realm_owner"]) self.assertTrue(prereg_realm.data_import_metadata["need_select_realm_owner"])
# Check that imported users have user provided email visibility setting.
test_user.refresh_from_db()
self.assertEqual(
test_user.email_address_visibility,
importer_set_email_address_visibility,
)
# Check that bots were not impacted by this setting.
test_bot_user.refresh_from_db()
self.assertEqual(
test_bot_user.email_address_visibility, UserProfile.EMAIL_ADDRESS_VISIBILITY_EVERYONE
)
# Confirmation key at this point is marked, used but since we # Confirmation key at this point is marked, used but since we
# are mocking the process, we need to do it manually here. # are mocking the process, we need to do it manually here.
get_object_from_key( get_object_from_key(

View File

@@ -2,6 +2,7 @@ import random
import string import string
from typing import TYPE_CHECKING, Any, cast from typing import TYPE_CHECKING, Any, cast
import orjson
from django.conf import settings from django.conf import settings
from django.http import HttpRequest, HttpResponse, HttpResponseRedirect from django.http import HttpRequest, HttpResponse, HttpResponseRedirect
from django.views.decorators.csrf import csrf_exempt from django.views.decorators.csrf import csrf_exempt
@@ -101,7 +102,7 @@ def register_demo_development_realm(request: HttpRequest) -> HttpResponse:
realm_name = generate_demo_realm_name() realm_name = generate_demo_realm_name()
realm_type = Realm.ORG_TYPES["unspecified"]["id"] realm_type = Realm.ORG_TYPES["unspecified"]["id"]
realm_subdomain = realm_name realm_subdomain = realm_name
email_address_visibility = UserProfile.EMAIL_ADDRESS_VISIBILITY_NOBODY email_address_visibility = orjson.dumps(UserProfile.EMAIL_ADDRESS_VISIBILITY_NOBODY)
prereg_realm = create_preregistration_realm( prereg_realm = create_preregistration_realm(
email, realm_name, realm_subdomain, realm_type, realm_default_language email, realm_name, realm_subdomain, realm_type, realm_default_language
) )

View File

@@ -18,7 +18,7 @@ from django.http import HttpRequest, HttpResponse, HttpResponseRedirect
from django.shortcuts import redirect, render from django.shortcuts import redirect, render
from django.template.response import TemplateResponse from django.template.response import TemplateResponse
from django.urls import reverse from django.urls import reverse
from django.utils.translation import get_language from django.utils.translation import get_language, gettext_lazy
from django.utils.translation import gettext as _ from django.utils.translation import gettext as _
from django_auth_ldap.backend import LDAPBackend, _LDAPUser from django_auth_ldap.backend import LDAPBackend, _LDAPUser
from pydantic import Json, NonNegativeInt, StringConstraints from pydantic import Json, NonNegativeInt, StringConstraints
@@ -31,7 +31,11 @@ from confirmation.models import (
get_object_from_key, get_object_from_key,
render_confirmation_key_error, render_confirmation_key_error,
) )
from zerver.actions.create_realm import do_create_realm from zerver.actions.create_realm import (
DEFAULT_EMAIL_ADDRESS_VISIBILITY_FOR_REALM,
do_create_realm,
get_email_address_visibility_default,
)
from zerver.actions.create_user import do_activate_mirror_dummy_user, do_create_user 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 (
@@ -271,6 +275,9 @@ def registration_helper(
source_realm_id: Annotated[NonNegativeInt | None, non_negative_int_or_none_validator()] = None, source_realm_id: Annotated[NonNegativeInt | None, non_negative_int_or_none_validator()] = None,
start_slack_import: Json[bool] = False, start_slack_import: Json[bool] = False,
timezone: Annotated[str, timezone_or_empty_validator()] = "", timezone: Annotated[str, timezone_or_empty_validator()] = "",
email_address_visibility: Annotated[
Json[int], check_int_in_validator(RealmUserDefault.EMAIL_ADDRESS_VISIBILITY_TYPES)
] = DEFAULT_EMAIL_ADDRESS_VISIBILITY_FOR_REALM,
) -> HttpResponse: ) -> HttpResponse:
try: try:
prereg_object, realm_creation = check_prereg_key(request, key) prereg_object, realm_creation = check_prereg_key(request, key)
@@ -326,6 +333,10 @@ def registration_helper(
assert prereg_realm.data_import_metadata.get("uploaded_import_file_name") is not None assert prereg_realm.data_import_metadata.get("uploaded_import_file_name") is not None
assert prereg_realm.data_import_metadata.get("is_import_work_queued") is not True assert prereg_realm.data_import_metadata.get("is_import_work_queued") is not True
assert prereg_realm.created_realm is None assert prereg_realm.created_realm is None
prereg_realm.data_import_metadata["email_address_visibility"] = email_address_visibility
prereg_realm.save(update_fields=["data_import_metadata"])
queue_json_publish_rollback_unsafe( queue_json_publish_rollback_unsafe(
"deferred_work", "deferred_work",
{ {
@@ -354,10 +365,23 @@ def registration_helper(
reverse("realm_import_post_process", kwargs={"confirmation_key": key}) reverse("realm_import_post_process", kwargs={"confirmation_key": key})
) )
# Set text of `EMAIL_ADDRESS_VISIBILITY_EVERYONE` to "Everyone" so that it doesn't overflow the
# select box in the slack import page.
email_address_visibility_options = []
for id, name in RealmUserDefault.EMAIL_ADDRESS_VISIBILITY_ID_TO_NAME_MAP.items():
if id == RealmUserDefault.EMAIL_ADDRESS_VISIBILITY_EVERYONE:
name = gettext_lazy("Everyone")
email_address_visibility_options.append((id, name))
assert is_realm_import_enabled() assert is_realm_import_enabled()
context: dict[str, Any] = { context: dict[str, Any] = {
"key": key, "key": key,
"max_file_size": settings.MAX_WEB_DATA_IMPORT_SIZE_MB, "max_file_size": settings.MAX_WEB_DATA_IMPORT_SIZE_MB,
"email_address_visibility_options": email_address_visibility_options,
"email_address_visibility_default": get_email_address_visibility_default(
prereg_realm.org_type
),
} }
saved_slack_access_token = prereg_realm.data_import_metadata.get("slack_access_token") saved_slack_access_token = prereg_realm.data_import_metadata.get("slack_access_token")