realm_creation_form: Capture import_from if realm import enabled.

We store user's preference for `import_from` to be acted upon in
later commits.
This commit is contained in:
Aman Agrawal
2025-04-29 12:25:16 +05:30
committed by Tim Abbott
parent 80e76d24e9
commit 5d4142e056
11 changed files with 61 additions and 17 deletions

View File

@@ -85,4 +85,26 @@
{% endif %}
</div>
</div>
{% if is_realm_import_enabled %}
<div class="input-box">
<div class="inline-block" id="realm-creation-import-from-wrapper">
<select id="import_from" name="import_from">
{% for key, choice in import_from_choices %}
<option value="{{ key }}" {% if key == "none" %}selected{% endif %}>{{ _(choice) }}</option>
{% endfor %}
</select>
<div class="not-editable-realm-field extra-info-realm-creation-import-from">
{% trans %}
You can also import from
<a href="/help/import-from-mattermost">Mattermost</a> or
<a href="/help/import-from-rocketchat">Rocket.Chat</a>.
{% endtrans %}
</div>
</div>
<label for="import_from" class="inline-block">
{{ _('Import chat history?') }}
</label>
</div>
{% endif %}
</div>

View File

@@ -22,7 +22,7 @@ from zerver.lib.realm_icon import get_realm_icon_url
from zerver.lib.request import RequestNotes
from zerver.lib.send_email import FromAddress
from zerver.lib.subdomains import get_subdomain, is_root_domain_available
from zerver.models import Realm, UserProfile
from zerver.models import PreregistrationRealm, Realm, UserProfile
from zerver.models.realms import get_realm
from zproject.backends import (
AUTH_BACKEND_NAME_MAP,
@@ -295,5 +295,6 @@ def get_realm_create_form_context() -> dict[str, Any]:
"root_domain_available": is_root_domain_available(),
"sorted_realm_types": sorted(Realm.ORG_TYPES.values(), key=lambda d: d["display_order"]),
"is_realm_import_enabled": is_realm_import_enabled(),
"import_from_choices": PreregistrationRealm.IMPORT_FROM_CHOICES,
}
return context

View File

@@ -38,7 +38,7 @@ from zerver.lib.name_restrictions import is_reserved_subdomain
from zerver.lib.rate_limiter import RateLimitedObject, rate_limit_request_by_ip
from zerver.lib.subdomains import get_subdomain, is_root_domain_available
from zerver.lib.users import check_full_name
from zerver.models import Realm, UserProfile
from zerver.models import PreregistrationRealm, Realm, UserProfile
from zerver.models.realm_audit_logs import RealmAuditLog
from zerver.models.realms import (
DisposableEmailError,
@@ -333,11 +333,19 @@ class HomepageForm(forms.Form):
class RealmCreationForm(RealmDetailsForm):
# This form determines whether users can create a new realm.
email = forms.EmailField(validators=[email_not_system_bot, email_is_not_disposable])
import_from = forms.ChoiceField(
choices=PreregistrationRealm.IMPORT_FROM_CHOICES,
required=False,
)
def __init__(self, *args: Any, **kwargs: Any) -> None:
kwargs["realm_creation"] = True
super().__init__(*args, **kwargs)
def clean_import_from(self) -> str:
# Convert "" to "none".
return self.cleaned_data["import_from"] or "none"
class AltchaWidget(forms.TextInput):
@override

View File

@@ -898,6 +898,7 @@ Output:
realm_default_language: str = "en",
realm_in_root_domain: str | None = None,
captcha: str | None = None,
import_from: str = "none",
) -> "TestHttpResponse":
payload = {
"email": email,
@@ -905,6 +906,7 @@ Output:
"realm_type": realm_type,
"realm_default_language": realm_default_language,
"realm_subdomain": realm_subdomain,
"import_from": import_from,
}
if captcha is not None:
payload["captcha"] = captcha

View File

@@ -50,6 +50,10 @@ class PreregistrationRealm(models.Model):
UserProfile, null=True, related_name="+", on_delete=models.SET_NULL
)
IMPORT_FROM_CHOICES = [
("none", "Don't import"),
("slack", "Import from Slack"),
]
data_import_metadata = models.JSONField(default=dict, encoder=DjangoJSONEncoder)

View File

@@ -306,6 +306,7 @@ class TestGenerateRealmCreationLink(ZulipTestCase):
"realm_type": Realm.ORG_TYPES["business"]["id"],
"realm_default_language": "en",
"realm_subdomain": "custom-test",
"import_from": "none",
},
)
self.assertEqual(result.status_code, 302)
@@ -334,6 +335,7 @@ class TestGenerateRealmCreationLink(ZulipTestCase):
"realm_type": Realm.ORG_TYPES["business"]["id"],
"realm_default_language": "en",
"realm_subdomain": string_id,
"import_from": "none",
},
)
self.assertEqual(result.status_code, 302)

View File

@@ -311,12 +311,10 @@ class TusdPreCreateTest(ZulipTestCase):
email,
realm_subdomain="ete-slack-import",
realm_name="Slack import end to end",
# TODO: Uncomment after adding support to form.
# import_from="slack",
import_from="slack",
)
prereg_realm = PreregistrationRealm.objects.get(email=email)
# TODO: Uncomment after adding support to form.
# self.assertEqual(prereg_realm.data_import_metadata["import_from"], "slack")
self.assertEqual(prereg_realm.data_import_metadata["import_from"], "slack")
prereg_realm.data_import_metadata["import_from"] = "slack"
prereg_realm.save()
@@ -392,12 +390,10 @@ class TusdPreCreateTest(ZulipTestCase):
email,
realm_subdomain="ete-slack-import",
realm_name="Slack import end to end",
# TODO: Uncomment after adding support to form.
# import_from="slack",
import_from="slack",
)
prereg_realm = PreregistrationRealm.objects.get(email=email)
# TODO: Uncomment after adding support to form.
# self.assertEqual(prereg_realm.data_import_metadata["import_from"], "slack")
self.assertEqual(prereg_realm.data_import_metadata["import_from"], "slack")
prereg_realm.data_import_metadata["import_from"] = "slack"
prereg_realm.save()
@@ -428,12 +424,10 @@ class TusdPreCreateTest(ZulipTestCase):
email,
realm_subdomain="ete-slack-import",
realm_name="Slack import end to end",
# TODO: Uncomment after adding support to form.
# import_from="slack",
import_from="slack",
)
prereg_realm = PreregistrationRealm.objects.get(email=email)
# TODO: Uncomment after adding support to form.
# self.assertEqual(prereg_realm.data_import_metadata["import_from"], "slack")
self.assertEqual(prereg_realm.data_import_metadata["import_from"], "slack")
prereg_realm.data_import_metadata["import_from"] = "slack"
prereg_realm.save()

View File

@@ -145,6 +145,7 @@ def create_preregistration_realm(
string_id: str,
org_type: int,
default_language: str,
import_from: str | None = None,
) -> PreregistrationRealm:
return PreregistrationRealm.objects.create(
email=email,
@@ -152,6 +153,7 @@ def create_preregistration_realm(
string_id=string_id,
org_type=org_type,
default_language=default_language,
data_import_metadata={"import_from": import_from},
)

View File

@@ -829,9 +829,15 @@ def prepare_realm_activation_url(
string_id: str,
org_type: int,
default_language: str,
import_form: str,
) -> str:
prereg_realm = create_preregistration_realm(
email, realm_name, string_id, org_type, default_language
email,
realm_name,
string_id,
org_type,
default_language,
import_form,
)
activation_url = create_confirmation_link(
prereg_realm, Confirmation.REALM_CREATION, no_associated_realm_object=True
@@ -928,6 +934,7 @@ def create_realm(request: HttpRequest, creation_key: str | None = None) -> HttpR
realm_type = form.cleaned_data["realm_type"]
realm_default_language = form.cleaned_data["realm_default_language"]
realm_subdomain = form.cleaned_data["realm_subdomain"]
import_from = form.cleaned_data["import_from"]
activation_url = prepare_realm_activation_url(
email,
request.session,
@@ -935,6 +942,7 @@ def create_realm(request: HttpRequest, creation_key: str | None = None) -> HttpR
realm_subdomain,
realm_type,
realm_default_language,
import_from,
)
if key_record is not None and key_record.presume_email_valid:
# The user has a token created from the server command line;

View File

@@ -698,12 +698,12 @@ CUSTOM_AUTHENTICATION_WRAPPER_FUNCTION: Callable[..., Any] | None = None
# notification.
RESOLVE_TOPIC_UNDO_GRACE_PERIOD_SECONDS = 60
# Maximum allowed size of uploaded file for realm import, in megabytes.
# Maximum allowed size of uploaded file for realm import on the web.
# 0 disables import; None means no limit.
#
# Note that this is a limit for the size of the uploaded export
# itself, not any additional files that may be imported as well.
MAX_WEB_DATA_IMPORT_SIZE_MB: int | None = 1024
MAX_WEB_DATA_IMPORT_SIZE_MB: int | None = 0
# Minimum and maximum permitted number of days before full data
# deletion when deactivating an organization. A nonzero minimum helps

View File

@@ -226,3 +226,4 @@ TOPIC_SUMMARIZATION_MODEL = "groq/llama-3.3-70b-versatile"
OUTPUT_COST_PER_GIGATOKEN = 590
INPUT_COST_PER_GIGATOKEN = 790
MAX_PER_USER_MONTHLY_AI_COST = 1
MAX_WEB_DATA_IMPORT_SIZE_MB = 1024