mirror of https://github.com/zulip/zulip.git
registration: Set the organization language at creation time.
In this commit, we add a new dropdown 'Organization language' on the `/new` and `/realm/register` pages. This dropdown allows setting the language of the organization during its creation. This allows messages from Welcome Bot and introductory messages in streams to be internationalized. Fixes a part of #25729.
This commit is contained in:
parent
f8aac58a6a
commit
ac1f711fef
|
@ -30,6 +30,7 @@ page can be easily identified in it's respective JavaScript file -->
|
||||||
<input type="hidden" class="email" id="email" value="{{ email }}" name="email"/>
|
<input type="hidden" class="email" id="email" value="{{ email }}" name="email"/>
|
||||||
<input type="hidden" class="realm_name" value="{{ new_realm_name }}" name="realm_name"/>
|
<input type="hidden" class="realm_name" value="{{ new_realm_name }}" name="realm_name"/>
|
||||||
<input type="hidden" class="realm_type" value="{{ realm_type }}" name="realm_type"/>
|
<input type="hidden" class="realm_type" value="{{ realm_type }}" name="realm_type"/>
|
||||||
|
<input type="hidden" class="realm_default_language" value="{{ realm_default_language }}" name="realm_default_language"/>
|
||||||
<input type="hidden" class="realm_subdomain" value="{{ realm_subdomain }}" name="realm_subdomain"/>
|
<input type="hidden" class="realm_subdomain" value="{{ realm_subdomain }}" name="realm_subdomain"/>
|
||||||
</form>
|
</form>
|
||||||
{% else %}
|
{% else %}
|
||||||
|
|
|
@ -34,6 +34,23 @@
|
||||||
<label for="realm_type" class="inline-block label-title">{{ _('Organization type') }}</label>
|
<label for="realm_type" class="inline-block label-title">{{ _('Organization type') }}</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="input-box">
|
||||||
|
<div class="inline-block relative">
|
||||||
|
<select name="realm_default_language" id="realm_default_language">
|
||||||
|
{% for language in language_list %}
|
||||||
|
<option value="{{ language.code }}" {% if form.realm_default_language.value() == language.code %}selected{% endif %} >{{ _(language.name) }}</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<label for="realm_default_language" class="inline-block label-title">
|
||||||
|
{{ _('Organization language') }}
|
||||||
|
<a href="/help/configure-organization-language" target="_blank" rel="noopener noreferrer">
|
||||||
|
<i class="fa fa-question-circle-o" aria-hidden="true"></i>
|
||||||
|
</a>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="input-box">
|
<div class="input-box">
|
||||||
<label class="static org-url">
|
<label class="static org-url">
|
||||||
{{ _('Organization URL') }}
|
{{ _('Organization URL') }}
|
||||||
|
|
|
@ -52,6 +52,10 @@ Form is validated both client-side using jquery-validation (see signup.js) and s
|
||||||
<label for="id_realm_type" class="inline-block label-title">{{ _('Organization type') }}</label>
|
<label for="id_realm_type" class="inline-block label-title">{{ _('Organization type') }}</label>
|
||||||
<div id="id_realm_type" class="not-editable-realm-field">{{ selected_realm_type_name }}</div>
|
<div id="id_realm_type" class="not-editable-realm-field">{{ selected_realm_type_name }}</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="input-box">
|
||||||
|
<label for="id_realm_default_language" class="inline-block label-title">{{ _('Organization language') }}</label>
|
||||||
|
<div id="id_realm_default_language" class="not-editable-realm-field">{{ selected_realm_default_language_name }}</div>
|
||||||
|
</div>
|
||||||
<div class="input-box">
|
<div class="input-box">
|
||||||
<label for="id_realm_subdomain" class="inline-block label-title">{{ _('Organization URL') }}</label>
|
<label for="id_realm_subdomain" class="inline-block label-title">{{ _('Organization URL') }}</label>
|
||||||
<div id="id_realm_subdomain" class="not-editable-realm-field">{% if form.realm_subdomain.value() %}{{ form.realm_subdomain.value() }}.{% endif %}{{external_host}}</div>
|
<div id="id_realm_subdomain" class="not-editable-realm-field">{% if form.realm_subdomain.value() %}{{ form.realm_subdomain.value() }}.{% endif %}{{external_host}}</div>
|
||||||
|
|
|
@ -159,6 +159,7 @@ def do_create_realm(
|
||||||
invite_required: Optional[bool] = None,
|
invite_required: Optional[bool] = None,
|
||||||
plan_type: Optional[int] = None,
|
plan_type: Optional[int] = None,
|
||||||
org_type: Optional[int] = None,
|
org_type: Optional[int] = None,
|
||||||
|
default_language: Optional[str] = None,
|
||||||
date_created: Optional[datetime.datetime] = None,
|
date_created: Optional[datetime.datetime] = None,
|
||||||
is_demo_organization: bool = False,
|
is_demo_organization: bool = False,
|
||||||
enable_read_receipts: Optional[bool] = None,
|
enable_read_receipts: Optional[bool] = None,
|
||||||
|
@ -184,6 +185,8 @@ def do_create_realm(
|
||||||
kwargs["plan_type"] = plan_type
|
kwargs["plan_type"] = plan_type
|
||||||
if org_type is not None:
|
if org_type is not None:
|
||||||
kwargs["org_type"] = org_type
|
kwargs["org_type"] = org_type
|
||||||
|
if default_language is not None:
|
||||||
|
kwargs["default_language"] = default_language
|
||||||
if enable_spectator_access is not None:
|
if enable_spectator_access is not None:
|
||||||
if enable_spectator_access:
|
if enable_spectator_access:
|
||||||
# Realms with LIMITED plan cannot have spectators enabled.
|
# Realms with LIMITED plan cannot have spectators enabled.
|
||||||
|
|
|
@ -14,6 +14,7 @@ from version import (
|
||||||
ZULIP_VERSION,
|
ZULIP_VERSION,
|
||||||
)
|
)
|
||||||
from zerver.lib.exceptions import InvalidSubdomainError
|
from zerver.lib.exceptions import InvalidSubdomainError
|
||||||
|
from zerver.lib.i18n import get_language_list
|
||||||
from zerver.lib.realm_description import get_realm_rendered_description, get_realm_text_description
|
from zerver.lib.realm_description import get_realm_rendered_description, get_realm_text_description
|
||||||
from zerver.lib.realm_icon import get_realm_icon_url
|
from zerver.lib.realm_icon import get_realm_icon_url
|
||||||
from zerver.lib.request import RequestNotes
|
from zerver.lib.request import RequestNotes
|
||||||
|
@ -259,6 +260,7 @@ def latest_info_context() -> Dict[str, str]:
|
||||||
|
|
||||||
def get_realm_create_form_context() -> Dict[str, Any]:
|
def get_realm_create_form_context() -> Dict[str, Any]:
|
||||||
context = {
|
context = {
|
||||||
|
"language_list": get_language_list(),
|
||||||
"MAX_REALM_NAME_LENGTH": str(Realm.MAX_REALM_NAME_LENGTH),
|
"MAX_REALM_NAME_LENGTH": str(Realm.MAX_REALM_NAME_LENGTH),
|
||||||
"MAX_REALM_SUBDOMAIN_LENGTH": str(Realm.MAX_REALM_SUBDOMAIN_LENGTH),
|
"MAX_REALM_SUBDOMAIN_LENGTH": str(Realm.MAX_REALM_SUBDOMAIN_LENGTH),
|
||||||
"root_domain_available": is_root_domain_available(),
|
"root_domain_available": is_root_domain_available(),
|
||||||
|
|
|
@ -28,6 +28,7 @@ from zerver.lib.email_validation import (
|
||||||
email_reserved_for_system_bots_error,
|
email_reserved_for_system_bots_error,
|
||||||
)
|
)
|
||||||
from zerver.lib.exceptions import JsonableError, RateLimitedError
|
from zerver.lib.exceptions import JsonableError, RateLimitedError
|
||||||
|
from zerver.lib.i18n import get_language_list
|
||||||
from zerver.lib.name_restrictions import is_disposable_domain, is_reserved_subdomain
|
from zerver.lib.name_restrictions import is_disposable_domain, is_reserved_subdomain
|
||||||
from zerver.lib.rate_limiter import RateLimitedObject, rate_limit_request_by_ip
|
from zerver.lib.rate_limiter import RateLimitedObject, rate_limit_request_by_ip
|
||||||
from zerver.lib.send_email import FromAddress, send_email
|
from zerver.lib.send_email import FromAddress, send_email
|
||||||
|
@ -140,6 +141,7 @@ class RealmDetailsForm(forms.Form):
|
||||||
realm_type = forms.TypedChoiceField(
|
realm_type = forms.TypedChoiceField(
|
||||||
coerce=int, choices=[(t["id"], t["name"]) for t in Realm.ORG_TYPES.values()]
|
coerce=int, choices=[(t["id"], t["name"]) for t in Realm.ORG_TYPES.values()]
|
||||||
)
|
)
|
||||||
|
realm_default_language = forms.ChoiceField(choices=[])
|
||||||
realm_name = forms.CharField(max_length=Realm.MAX_REALM_NAME_LENGTH)
|
realm_name = forms.CharField(max_length=Realm.MAX_REALM_NAME_LENGTH)
|
||||||
|
|
||||||
def __init__(self, *args: Any, **kwargs: Any) -> None:
|
def __init__(self, *args: Any, **kwargs: Any) -> None:
|
||||||
|
@ -147,6 +149,9 @@ class RealmDetailsForm(forms.Form):
|
||||||
del kwargs["realm_creation"]
|
del kwargs["realm_creation"]
|
||||||
|
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
self.fields["realm_default_language"] = forms.ChoiceField(
|
||||||
|
choices=[(lang["code"], lang["name"]) for lang in get_language_list()],
|
||||||
|
)
|
||||||
|
|
||||||
def clean_realm_subdomain(self) -> str:
|
def clean_realm_subdomain(self) -> str:
|
||||||
if not self.realm_creation:
|
if not self.realm_creation:
|
||||||
|
@ -192,6 +197,10 @@ class RegistrationForm(RealmDetailsForm):
|
||||||
choices=[(t["id"], t["name"]) for t in Realm.ORG_TYPES.values()],
|
choices=[(t["id"], t["name"]) for t in Realm.ORG_TYPES.values()],
|
||||||
required=self.realm_creation,
|
required=self.realm_creation,
|
||||||
)
|
)
|
||||||
|
self.fields["realm_default_language"] = forms.ChoiceField(
|
||||||
|
choices=[(lang["code"], lang["name"]) for lang in get_language_list()],
|
||||||
|
required=self.realm_creation,
|
||||||
|
)
|
||||||
|
|
||||||
def clean_full_name(self) -> str:
|
def clean_full_name(self) -> str:
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -820,6 +820,7 @@ Output:
|
||||||
source_realm_id: str = "",
|
source_realm_id: str = "",
|
||||||
key: Optional[str] = None,
|
key: Optional[str] = None,
|
||||||
realm_type: int = Realm.ORG_TYPES["business"]["id"],
|
realm_type: int = Realm.ORG_TYPES["business"]["id"],
|
||||||
|
realm_default_language: str = "en",
|
||||||
enable_marketing_emails: Optional[bool] = None,
|
enable_marketing_emails: Optional[bool] = None,
|
||||||
email_address_visibility: Optional[int] = None,
|
email_address_visibility: Optional[int] = None,
|
||||||
is_demo_organization: bool = False,
|
is_demo_organization: bool = False,
|
||||||
|
@ -840,6 +841,7 @@ Output:
|
||||||
"realm_name": realm_name,
|
"realm_name": realm_name,
|
||||||
"realm_subdomain": realm_subdomain,
|
"realm_subdomain": realm_subdomain,
|
||||||
"realm_type": realm_type,
|
"realm_type": realm_type,
|
||||||
|
"realm_default_language": realm_default_language,
|
||||||
"key": key if key is not None else find_key_by_email(email),
|
"key": key if key is not None else find_key_by_email(email),
|
||||||
"timezone": timezone,
|
"timezone": timezone,
|
||||||
"terms": True,
|
"terms": True,
|
||||||
|
@ -874,12 +876,14 @@ Output:
|
||||||
realm_subdomain: str,
|
realm_subdomain: str,
|
||||||
realm_name: str,
|
realm_name: str,
|
||||||
realm_type: int = Realm.ORG_TYPES["business"]["id"],
|
realm_type: int = Realm.ORG_TYPES["business"]["id"],
|
||||||
|
realm_default_language: str = "en",
|
||||||
realm_in_root_domain: Optional[str] = None,
|
realm_in_root_domain: Optional[str] = None,
|
||||||
) -> "TestHttpResponse":
|
) -> "TestHttpResponse":
|
||||||
payload = {
|
payload = {
|
||||||
"email": email,
|
"email": email,
|
||||||
"realm_name": realm_name,
|
"realm_name": realm_name,
|
||||||
"realm_type": realm_type,
|
"realm_type": realm_type,
|
||||||
|
"realm_default_language": realm_default_language,
|
||||||
"realm_subdomain": realm_subdomain,
|
"realm_subdomain": realm_subdomain,
|
||||||
}
|
}
|
||||||
if realm_in_root_domain is not None:
|
if realm_in_root_domain is not None:
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
# Generated by Django 4.2.5 on 2023-09-12 19:58
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
dependencies = [
|
||||||
|
(
|
||||||
|
"zerver",
|
||||||
|
"0483_rename_escape_navigates_to_default_view_realmuserdefault_web_escape_navigates_to_home_view_and_more",
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="preregistrationrealm",
|
||||||
|
name="default_language",
|
||||||
|
field=models.CharField(default="en", max_length=50),
|
||||||
|
),
|
||||||
|
]
|
|
@ -2434,6 +2434,10 @@ class PreregistrationRealm(models.Model):
|
||||||
default=Realm.ORG_TYPES["unspecified"]["id"],
|
default=Realm.ORG_TYPES["unspecified"]["id"],
|
||||||
choices=[(t["id"], t["name"]) for t in Realm.ORG_TYPES.values()],
|
choices=[(t["id"], t["name"]) for t in Realm.ORG_TYPES.values()],
|
||||||
)
|
)
|
||||||
|
default_language = models.CharField(
|
||||||
|
default="en",
|
||||||
|
max_length=MAX_LANGUAGE_ID_LENGTH,
|
||||||
|
)
|
||||||
string_id = models.CharField(max_length=Realm.MAX_REALM_SUBDOMAIN_LENGTH)
|
string_id = models.CharField(max_length=Realm.MAX_REALM_SUBDOMAIN_LENGTH)
|
||||||
email = models.EmailField()
|
email = models.EmailField()
|
||||||
|
|
||||||
|
|
|
@ -310,6 +310,7 @@ class TestGenerateRealmCreationLink(ZulipTestCase):
|
||||||
"email": email,
|
"email": email,
|
||||||
"realm_name": "Zulip test",
|
"realm_name": "Zulip test",
|
||||||
"realm_type": Realm.ORG_TYPES["business"]["id"],
|
"realm_type": Realm.ORG_TYPES["business"]["id"],
|
||||||
|
"realm_default_language": "en",
|
||||||
"realm_subdomain": "custom-test",
|
"realm_subdomain": "custom-test",
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
@ -337,12 +338,13 @@ class TestGenerateRealmCreationLink(ZulipTestCase):
|
||||||
"email": email,
|
"email": email,
|
||||||
"realm_name": realm_name,
|
"realm_name": realm_name,
|
||||||
"realm_type": Realm.ORG_TYPES["business"]["id"],
|
"realm_type": Realm.ORG_TYPES["business"]["id"],
|
||||||
|
"realm_default_language": "en",
|
||||||
"realm_subdomain": string_id,
|
"realm_subdomain": string_id,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
self.assertEqual(result.status_code, 302)
|
self.assertEqual(result.status_code, 302)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
f"/accounts/new/send_confirm/?email={urllib.parse.quote(email)}&realm_name={urllib.parse.quote_plus(realm_name)}&realm_type=10&realm_subdomain={string_id}",
|
f"/accounts/new/send_confirm/?email={urllib.parse.quote(email)}&realm_name={urllib.parse.quote_plus(realm_name)}&realm_type=10&realm_default_language=en&realm_subdomain={string_id}",
|
||||||
result["Location"],
|
result["Location"],
|
||||||
)
|
)
|
||||||
result = self.client_get(result["Location"])
|
result = self.client_get(result["Location"])
|
||||||
|
|
|
@ -748,7 +748,7 @@ class PasswordResetTest(ZulipTestCase):
|
||||||
self.assert_in_success_response(["/accounts/home/"], result)
|
self.assert_in_success_response(["/accounts/home/"], result)
|
||||||
|
|
||||||
result = self.client_get(
|
result = self.client_get(
|
||||||
"/accounts/new/send_confirm/?email=alice@example.com&realm_name=Zulip+test&realm_type=10&realm_subdomain=zuliptest"
|
"/accounts/new/send_confirm/?email=alice@example.com&realm_name=Zulip+test&realm_type=10&realm_default_language=en&realm_subdomain=zuliptest"
|
||||||
)
|
)
|
||||||
self.assert_in_success_response(["/new/"], result)
|
self.assert_in_success_response(["/new/"], result)
|
||||||
|
|
||||||
|
@ -1256,7 +1256,7 @@ class RealmCreationTest(ZulipTestCase):
|
||||||
self.assertEqual(result.status_code, 302)
|
self.assertEqual(result.status_code, 302)
|
||||||
self.assertTrue(
|
self.assertTrue(
|
||||||
result["Location"].endswith(
|
result["Location"].endswith(
|
||||||
f"/accounts/new/send_confirm/?email={urllib.parse.quote(email)}&realm_name={urllib.parse.quote_plus(org_name)}&realm_type=10&realm_subdomain={string_id}"
|
f"/accounts/new/send_confirm/?email={urllib.parse.quote(email)}&realm_name={urllib.parse.quote_plus(org_name)}&realm_type=10&realm_default_language=en&realm_subdomain={string_id}"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
result = self.client_get(result["Location"])
|
result = self.client_get(result["Location"])
|
||||||
|
@ -1264,6 +1264,7 @@ class RealmCreationTest(ZulipTestCase):
|
||||||
prereg_realm = PreregistrationRealm.objects.get(email=email)
|
prereg_realm = PreregistrationRealm.objects.get(email=email)
|
||||||
self.assertEqual(prereg_realm.name, "Zulip Test")
|
self.assertEqual(prereg_realm.name, "Zulip Test")
|
||||||
self.assertEqual(prereg_realm.org_type, Realm.ORG_TYPES["business"]["id"])
|
self.assertEqual(prereg_realm.org_type, Realm.ORG_TYPES["business"]["id"])
|
||||||
|
self.assertEqual(prereg_realm.default_language, "en")
|
||||||
self.assertEqual(prereg_realm.string_id, string_id)
|
self.assertEqual(prereg_realm.string_id, string_id)
|
||||||
|
|
||||||
# Check confirmation email has the correct subject and body, extract
|
# Check confirmation email has the correct subject and body, extract
|
||||||
|
@ -1295,6 +1296,7 @@ class RealmCreationTest(ZulipTestCase):
|
||||||
|
|
||||||
# Check defaults
|
# Check defaults
|
||||||
self.assertEqual(realm.org_type, Realm.ORG_TYPES["business"]["id"])
|
self.assertEqual(realm.org_type, Realm.ORG_TYPES["business"]["id"])
|
||||||
|
self.assertEqual(realm.default_language, "en")
|
||||||
self.assertEqual(realm.emails_restricted_to_domains, False)
|
self.assertEqual(realm.emails_restricted_to_domains, False)
|
||||||
self.assertEqual(realm.invite_required, True)
|
self.assertEqual(realm.invite_required, True)
|
||||||
|
|
||||||
|
@ -1397,7 +1399,7 @@ class RealmCreationTest(ZulipTestCase):
|
||||||
self.assertEqual(result.status_code, 302)
|
self.assertEqual(result.status_code, 302)
|
||||||
self.assertTrue(
|
self.assertTrue(
|
||||||
result["Location"].endswith(
|
result["Location"].endswith(
|
||||||
f"/accounts/new/send_confirm/?email={urllib.parse.quote(email)}&realm_name={urllib.parse.quote_plus(realm_name)}&realm_type=10&realm_subdomain={string_id}"
|
f"/accounts/new/send_confirm/?email={urllib.parse.quote(email)}&realm_name={urllib.parse.quote_plus(realm_name)}&realm_type=10&realm_default_language=en&realm_subdomain={string_id}"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
result = self.client_get(result["Location"])
|
result = self.client_get(result["Location"])
|
||||||
|
@ -1443,7 +1445,7 @@ class RealmCreationTest(ZulipTestCase):
|
||||||
self.assertEqual(result.status_code, 302)
|
self.assertEqual(result.status_code, 302)
|
||||||
self.assertTrue(
|
self.assertTrue(
|
||||||
result["Location"].endswith(
|
result["Location"].endswith(
|
||||||
f"/accounts/new/send_confirm/?email={urllib.parse.quote(email)}&realm_name={urllib.parse.quote_plus(realm_name)}&realm_type=10&realm_subdomain={string_id}"
|
f"/accounts/new/send_confirm/?email={urllib.parse.quote(email)}&realm_name={urllib.parse.quote_plus(realm_name)}&realm_type=10&realm_default_language=en&realm_subdomain={string_id}"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
result = self.client_get(result["Location"])
|
result = self.client_get(result["Location"])
|
||||||
|
@ -1492,7 +1494,7 @@ class RealmCreationTest(ZulipTestCase):
|
||||||
self.assertEqual(result.status_code, 302)
|
self.assertEqual(result.status_code, 302)
|
||||||
self.assertTrue(
|
self.assertTrue(
|
||||||
result["Location"].endswith(
|
result["Location"].endswith(
|
||||||
f"/accounts/new/send_confirm/?email={urllib.parse.quote(email)}&realm_name={urllib.parse.quote_plus(realm_name)}&realm_type=10&realm_subdomain={string_id}"
|
f"/accounts/new/send_confirm/?email={urllib.parse.quote(email)}&realm_name={urllib.parse.quote_plus(realm_name)}&realm_type=10&realm_default_language=en&realm_subdomain={string_id}"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
result = self.client_get(result["Location"])
|
result = self.client_get(result["Location"])
|
||||||
|
@ -1552,7 +1554,7 @@ class RealmCreationTest(ZulipTestCase):
|
||||||
self.assertEqual(result.status_code, 302)
|
self.assertEqual(result.status_code, 302)
|
||||||
self.assertTrue(
|
self.assertTrue(
|
||||||
result["Location"].endswith(
|
result["Location"].endswith(
|
||||||
f"/accounts/new/send_confirm/?email={urllib.parse.quote(email)}&realm_name={urllib.parse.quote_plus(realm_name)}&realm_type=10&realm_subdomain={string_id}"
|
f"/accounts/new/send_confirm/?email={urllib.parse.quote(email)}&realm_name={urllib.parse.quote_plus(realm_name)}&realm_type=10&realm_default_language=en&realm_subdomain={string_id}"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
result = self.client_get(result["Location"])
|
result = self.client_get(result["Location"])
|
||||||
|
@ -1597,7 +1599,7 @@ class RealmCreationTest(ZulipTestCase):
|
||||||
self.assertEqual(result.status_code, 302)
|
self.assertEqual(result.status_code, 302)
|
||||||
self.assertTrue(
|
self.assertTrue(
|
||||||
result["Location"].endswith(
|
result["Location"].endswith(
|
||||||
f"/accounts/new/send_confirm/?email={urllib.parse.quote(email)}&realm_name={urllib.parse.quote_plus(realm_name)}&realm_type=10&realm_subdomain={string_id}"
|
f"/accounts/new/send_confirm/?email={urllib.parse.quote(email)}&realm_name={urllib.parse.quote_plus(realm_name)}&realm_type=10&realm_default_language=en&realm_subdomain={string_id}"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
result = self.client_get(result["Location"])
|
result = self.client_get(result["Location"])
|
||||||
|
@ -1648,7 +1650,7 @@ class RealmCreationTest(ZulipTestCase):
|
||||||
self.assertEqual(result.status_code, 302)
|
self.assertEqual(result.status_code, 302)
|
||||||
self.assertTrue(
|
self.assertTrue(
|
||||||
result["Location"].endswith(
|
result["Location"].endswith(
|
||||||
f"/accounts/new/send_confirm/?email={urllib.parse.quote(email)}&realm_name={urllib.parse.quote_plus(realm_name)}&realm_type=35&realm_subdomain={string_id}"
|
f"/accounts/new/send_confirm/?email={urllib.parse.quote(email)}&realm_name={urllib.parse.quote_plus(realm_name)}&realm_type=35&realm_default_language=en&realm_subdomain={string_id}"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
result = self.client_get(result["Location"])
|
result = self.client_get(result["Location"])
|
||||||
|
@ -1683,6 +1685,61 @@ class RealmCreationTest(ZulipTestCase):
|
||||||
self.assertIn("Using Zulip for a class guide", welcome_msg.content)
|
self.assertIn("Using Zulip for a class guide", welcome_msg.content)
|
||||||
self.assertIn("demo organization", welcome_msg.content)
|
self.assertIn("demo organization", welcome_msg.content)
|
||||||
|
|
||||||
|
@override_settings(OPEN_REALM_CREATION=True)
|
||||||
|
def test_create_realm_with_custom_language(self) -> None:
|
||||||
|
email = "user1@test.com"
|
||||||
|
password = "test"
|
||||||
|
string_id = "custom-test"
|
||||||
|
realm_name = "Zulip Test"
|
||||||
|
realm_language = "it"
|
||||||
|
|
||||||
|
# Make sure the realm does not exist
|
||||||
|
with self.assertRaises(Realm.DoesNotExist):
|
||||||
|
get_realm(string_id)
|
||||||
|
|
||||||
|
# Create new realm with the email
|
||||||
|
result = self.submit_realm_creation_form(
|
||||||
|
email,
|
||||||
|
realm_subdomain=string_id,
|
||||||
|
realm_name=realm_name,
|
||||||
|
realm_default_language=realm_language,
|
||||||
|
)
|
||||||
|
self.assertEqual(result.status_code, 302)
|
||||||
|
self.assertTrue(
|
||||||
|
result["Location"].endswith(
|
||||||
|
f"/accounts/new/send_confirm/?email={urllib.parse.quote(email)}&realm_name={urllib.parse.quote_plus(realm_name)}&realm_type=10&realm_default_language={realm_language}&realm_subdomain={string_id}"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
result = self.client_get(result["Location"])
|
||||||
|
self.assert_in_response("check your email", result)
|
||||||
|
|
||||||
|
prereg_realm = PreregistrationRealm.objects.get(email=email)
|
||||||
|
# Check default_language field of PreregistrationRealm object
|
||||||
|
self.assertEqual(prereg_realm.default_language, realm_language)
|
||||||
|
|
||||||
|
# Visit the confirmation link.
|
||||||
|
confirmation_url = self.get_confirmation_url_from_outbox(email)
|
||||||
|
result = self.client_get(confirmation_url)
|
||||||
|
self.assertEqual(result.status_code, 200)
|
||||||
|
|
||||||
|
result = self.submit_reg_form_for_user(
|
||||||
|
email,
|
||||||
|
password,
|
||||||
|
realm_subdomain=string_id,
|
||||||
|
realm_name=realm_name,
|
||||||
|
realm_default_language=realm_language,
|
||||||
|
)
|
||||||
|
self.assertEqual(result.status_code, 302)
|
||||||
|
|
||||||
|
result = self.client_get(result["Location"], subdomain=string_id)
|
||||||
|
self.assertEqual(result.status_code, 302)
|
||||||
|
self.assertEqual(result["Location"], "http://custom-test.testserver")
|
||||||
|
|
||||||
|
# Make sure the realm is created and check default_language field
|
||||||
|
realm = get_realm(string_id)
|
||||||
|
self.assertEqual(realm.string_id, string_id)
|
||||||
|
self.assertEqual(realm.default_language, realm_language)
|
||||||
|
|
||||||
@override_settings(OPEN_REALM_CREATION=True, FREE_TRIAL_DAYS=30)
|
@override_settings(OPEN_REALM_CREATION=True, FREE_TRIAL_DAYS=30)
|
||||||
def test_create_realm_during_free_trial(self) -> None:
|
def test_create_realm_during_free_trial(self) -> None:
|
||||||
password = "test"
|
password = "test"
|
||||||
|
@ -1700,7 +1757,7 @@ class RealmCreationTest(ZulipTestCase):
|
||||||
self.assertEqual(result.status_code, 302)
|
self.assertEqual(result.status_code, 302)
|
||||||
self.assertTrue(
|
self.assertTrue(
|
||||||
result["Location"].endswith(
|
result["Location"].endswith(
|
||||||
f"/accounts/new/send_confirm/?email={urllib.parse.quote(email)}&realm_name={urllib.parse.quote_plus(realm_name)}&realm_type=10&realm_subdomain={string_id}"
|
f"/accounts/new/send_confirm/?email={urllib.parse.quote(email)}&realm_name={urllib.parse.quote_plus(realm_name)}&realm_type=10&realm_default_language=en&realm_subdomain={string_id}"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
result = self.client_get(result["Location"])
|
result = self.client_get(result["Location"])
|
||||||
|
@ -1756,7 +1813,7 @@ class RealmCreationTest(ZulipTestCase):
|
||||||
self.assertEqual(result.status_code, 302)
|
self.assertEqual(result.status_code, 302)
|
||||||
self.assertTrue(
|
self.assertTrue(
|
||||||
result["Location"].endswith(
|
result["Location"].endswith(
|
||||||
f"/accounts/new/send_confirm/?email={urllib.parse.quote(email)}&realm_name={urllib.parse.quote_plus(first_realm_name)}&realm_type=10&realm_subdomain={first_string_id}"
|
f"/accounts/new/send_confirm/?email={urllib.parse.quote(email)}&realm_name={urllib.parse.quote_plus(first_realm_name)}&realm_type=10&realm_default_language=en&realm_subdomain={first_string_id}"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
result = self.client_get(result["Location"])
|
result = self.client_get(result["Location"])
|
||||||
|
@ -1770,7 +1827,7 @@ class RealmCreationTest(ZulipTestCase):
|
||||||
self.assertEqual(result.status_code, 302)
|
self.assertEqual(result.status_code, 302)
|
||||||
self.assertTrue(
|
self.assertTrue(
|
||||||
result["Location"].endswith(
|
result["Location"].endswith(
|
||||||
f"/accounts/new/send_confirm/?email={urllib.parse.quote(email)}&realm_name={urllib.parse.quote_plus(second_realm_name)}&realm_type=10&realm_subdomain={second_string_id}"
|
f"/accounts/new/send_confirm/?email={urllib.parse.quote(email)}&realm_name={urllib.parse.quote_plus(second_realm_name)}&realm_type=10&realm_default_language=en&realm_subdomain={second_string_id}"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
result = self.client_get(result["Location"])
|
result = self.client_get(result["Location"])
|
||||||
|
|
|
@ -143,12 +143,14 @@ def create_preregistration_realm(
|
||||||
name: str,
|
name: str,
|
||||||
string_id: str,
|
string_id: str,
|
||||||
org_type: int,
|
org_type: int,
|
||||||
|
default_language: str,
|
||||||
) -> PreregistrationRealm:
|
) -> PreregistrationRealm:
|
||||||
return PreregistrationRealm.objects.create(
|
return PreregistrationRealm.objects.create(
|
||||||
email=email,
|
email=email,
|
||||||
name=name,
|
name=name,
|
||||||
string_id=string_id,
|
string_id=string_id,
|
||||||
org_type=org_type,
|
org_type=org_type,
|
||||||
|
default_language=default_language,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -65,8 +65,11 @@ def register_development_realm(request: HttpRequest) -> HttpResponse:
|
||||||
email = f"{name}@zulip.com"
|
email = f"{name}@zulip.com"
|
||||||
realm_name = f"realm-{count}"
|
realm_name = f"realm-{count}"
|
||||||
realm_type = Realm.ORG_TYPES["business"]["id"]
|
realm_type = Realm.ORG_TYPES["business"]["id"]
|
||||||
|
realm_default_language = "en"
|
||||||
realm_subdomain = realm_name
|
realm_subdomain = realm_name
|
||||||
prereg_realm = create_preregistration_realm(email, realm_name, realm_subdomain, realm_type)
|
prereg_realm = create_preregistration_realm(
|
||||||
|
email, realm_name, realm_subdomain, realm_type, realm_default_language
|
||||||
|
)
|
||||||
activation_url = create_confirmation_link(
|
activation_url = create_confirmation_link(
|
||||||
prereg_realm, Confirmation.REALM_CREATION, realm_creation=True
|
prereg_realm, Confirmation.REALM_CREATION, realm_creation=True
|
||||||
)
|
)
|
||||||
|
@ -77,6 +80,7 @@ def register_development_realm(request: HttpRequest) -> HttpResponse:
|
||||||
key=key,
|
key=key,
|
||||||
realm_name=realm_name,
|
realm_name=realm_name,
|
||||||
realm_type=realm_type,
|
realm_type=realm_type,
|
||||||
|
realm_default_language=realm_default_language,
|
||||||
full_name=name,
|
full_name=name,
|
||||||
password="test",
|
password="test",
|
||||||
realm_subdomain=realm_subdomain,
|
realm_subdomain=realm_subdomain,
|
||||||
|
@ -91,11 +95,14 @@ def register_demo_development_realm(request: HttpRequest) -> HttpResponse:
|
||||||
# Demo organization owners are not required to provide a name or email.
|
# Demo organization owners are not required to provide a name or email.
|
||||||
name = "Your name"
|
name = "Your name"
|
||||||
email = ""
|
email = ""
|
||||||
|
realm_default_language = "en"
|
||||||
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 = UserProfile.EMAIL_ADDRESS_VISIBILITY_NOBODY
|
||||||
prereg_realm = create_preregistration_realm(email, realm_name, realm_subdomain, realm_type)
|
prereg_realm = create_preregistration_realm(
|
||||||
|
email, realm_name, realm_subdomain, realm_type, realm_default_language
|
||||||
|
)
|
||||||
activation_url = create_confirmation_link(
|
activation_url = create_confirmation_link(
|
||||||
prereg_realm, Confirmation.REALM_CREATION, realm_creation=True
|
prereg_realm, Confirmation.REALM_CREATION, realm_creation=True
|
||||||
)
|
)
|
||||||
|
@ -106,6 +113,7 @@ def register_demo_development_realm(request: HttpRequest) -> HttpResponse:
|
||||||
key=key,
|
key=key,
|
||||||
realm_name=realm_name,
|
realm_name=realm_name,
|
||||||
realm_type=realm_type,
|
realm_type=realm_type,
|
||||||
|
realm_default_language=realm_default_language,
|
||||||
email_address_visibility=email_address_visibility,
|
email_address_visibility=email_address_visibility,
|
||||||
full_name=name,
|
full_name=name,
|
||||||
password="test",
|
password="test",
|
||||||
|
|
|
@ -52,7 +52,11 @@ from zerver.forms import (
|
||||||
)
|
)
|
||||||
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 RateLimitedError
|
from zerver.lib.exceptions import RateLimitedError
|
||||||
from zerver.lib.i18n import get_default_language_for_new_user
|
from zerver.lib.i18n import (
|
||||||
|
get_browser_language_code,
|
||||||
|
get_default_language_for_new_user,
|
||||||
|
get_language_name,
|
||||||
|
)
|
||||||
from zerver.lib.pysa import mark_sanitized
|
from zerver.lib.pysa import mark_sanitized
|
||||||
from zerver.lib.rate_limiter import rate_limit_request_by_ip
|
from zerver.lib.rate_limiter import rate_limit_request_by_ip
|
||||||
from zerver.lib.request import REQ, has_request_variables
|
from zerver.lib.request import REQ, has_request_variables
|
||||||
|
@ -70,6 +74,7 @@ from zerver.lib.validator import (
|
||||||
)
|
)
|
||||||
from zerver.lib.zephyr import compute_mit_user_fullname
|
from zerver.lib.zephyr import compute_mit_user_fullname
|
||||||
from zerver.models import (
|
from zerver.models import (
|
||||||
|
MAX_LANGUAGE_ID_LENGTH,
|
||||||
DisposableEmailError,
|
DisposableEmailError,
|
||||||
DomainNotAllowedForRealmError,
|
DomainNotAllowedForRealmError,
|
||||||
EmailContainsPlusError,
|
EmailContainsPlusError,
|
||||||
|
@ -195,6 +200,16 @@ def get_selected_realm_type_name(prereg_realm: Optional[PreregistrationRealm]) -
|
||||||
return get_org_type_display_name(prereg_realm.org_type)
|
return get_org_type_display_name(prereg_realm.org_type)
|
||||||
|
|
||||||
|
|
||||||
|
def get_selected_realm_default_language_name(
|
||||||
|
prereg_realm: Optional[PreregistrationRealm],
|
||||||
|
) -> Optional[str]:
|
||||||
|
if prereg_realm is None:
|
||||||
|
# We show the selected realm language only when creating new realm.
|
||||||
|
return None
|
||||||
|
|
||||||
|
return get_language_name(prereg_realm.default_language)
|
||||||
|
|
||||||
|
|
||||||
@add_google_analytics
|
@add_google_analytics
|
||||||
@require_post
|
@require_post
|
||||||
def realm_register(*args: Any, **kwargs: Any) -> HttpResponse:
|
def realm_register(*args: Any, **kwargs: Any) -> HttpResponse:
|
||||||
|
@ -361,6 +376,7 @@ def registration_helper(
|
||||||
initial_data = {
|
initial_data = {
|
||||||
"realm_name": prereg_realm.name,
|
"realm_name": prereg_realm.name,
|
||||||
"realm_type": prereg_realm.org_type,
|
"realm_type": prereg_realm.org_type,
|
||||||
|
"realm_default_language": prereg_realm.default_language,
|
||||||
"realm_subdomain": prereg_realm.string_id,
|
"realm_subdomain": prereg_realm.string_id,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -440,11 +456,13 @@ def registration_helper(
|
||||||
string_id = form.cleaned_data["realm_subdomain"]
|
string_id = form.cleaned_data["realm_subdomain"]
|
||||||
realm_name = form.cleaned_data["realm_name"]
|
realm_name = form.cleaned_data["realm_name"]
|
||||||
realm_type = form.cleaned_data["realm_type"]
|
realm_type = form.cleaned_data["realm_type"]
|
||||||
|
realm_default_language = form.cleaned_data["realm_default_language"]
|
||||||
is_demo_organization = form.cleaned_data["is_demo_organization"]
|
is_demo_organization = form.cleaned_data["is_demo_organization"]
|
||||||
realm = do_create_realm(
|
realm = do_create_realm(
|
||||||
string_id,
|
string_id,
|
||||||
realm_name,
|
realm_name,
|
||||||
org_type=realm_type,
|
org_type=realm_type,
|
||||||
|
default_language=realm_default_language,
|
||||||
is_demo_organization=is_demo_organization,
|
is_demo_organization=is_demo_organization,
|
||||||
prereg_realm=prereg_realm,
|
prereg_realm=prereg_realm,
|
||||||
)
|
)
|
||||||
|
@ -654,6 +672,9 @@ def registration_helper(
|
||||||
"corporate_enabled": settings.CORPORATE_ENABLED,
|
"corporate_enabled": settings.CORPORATE_ENABLED,
|
||||||
"default_email_address_visibility": default_email_address_visibility,
|
"default_email_address_visibility": default_email_address_visibility,
|
||||||
"selected_realm_type_name": get_selected_realm_type_name(prereg_realm),
|
"selected_realm_type_name": get_selected_realm_type_name(prereg_realm),
|
||||||
|
"selected_realm_default_language_name": get_selected_realm_default_language_name(
|
||||||
|
prereg_realm
|
||||||
|
),
|
||||||
"email_address_visibility_admins_only": RealmUserDefault.EMAIL_ADDRESS_VISIBILITY_ADMINS,
|
"email_address_visibility_admins_only": RealmUserDefault.EMAIL_ADDRESS_VISIBILITY_ADMINS,
|
||||||
"email_address_visibility_moderators": RealmUserDefault.EMAIL_ADDRESS_VISIBILITY_MODERATORS,
|
"email_address_visibility_moderators": RealmUserDefault.EMAIL_ADDRESS_VISIBILITY_MODERATORS,
|
||||||
"email_address_visibility_nobody": RealmUserDefault.EMAIL_ADDRESS_VISIBILITY_NOBODY,
|
"email_address_visibility_nobody": RealmUserDefault.EMAIL_ADDRESS_VISIBILITY_NOBODY,
|
||||||
|
@ -727,8 +748,11 @@ def prepare_realm_activation_url(
|
||||||
realm_name: str,
|
realm_name: str,
|
||||||
string_id: str,
|
string_id: str,
|
||||||
org_type: int,
|
org_type: int,
|
||||||
|
default_language: str,
|
||||||
) -> str:
|
) -> str:
|
||||||
prereg_realm = create_preregistration_realm(email, realm_name, string_id, org_type)
|
prereg_realm = create_preregistration_realm(
|
||||||
|
email, realm_name, string_id, org_type, default_language
|
||||||
|
)
|
||||||
activation_url = create_confirmation_link(
|
activation_url = create_confirmation_link(
|
||||||
prereg_realm, Confirmation.REALM_CREATION, realm_creation=True
|
prereg_realm, Confirmation.REALM_CREATION, realm_creation=True
|
||||||
)
|
)
|
||||||
|
@ -802,9 +826,15 @@ def create_realm(request: HttpRequest, creation_key: Optional[str] = None) -> Ht
|
||||||
email = form.cleaned_data["email"]
|
email = form.cleaned_data["email"]
|
||||||
realm_name = form.cleaned_data["realm_name"]
|
realm_name = form.cleaned_data["realm_name"]
|
||||||
realm_type = form.cleaned_data["realm_type"]
|
realm_type = form.cleaned_data["realm_type"]
|
||||||
|
realm_default_language = form.cleaned_data["realm_default_language"]
|
||||||
realm_subdomain = form.cleaned_data["realm_subdomain"]
|
realm_subdomain = form.cleaned_data["realm_subdomain"]
|
||||||
activation_url = prepare_realm_activation_url(
|
activation_url = prepare_realm_activation_url(
|
||||||
email, request.session, realm_name, realm_subdomain, realm_type
|
email,
|
||||||
|
request.session,
|
||||||
|
realm_name,
|
||||||
|
realm_subdomain,
|
||||||
|
realm_type,
|
||||||
|
realm_default_language,
|
||||||
)
|
)
|
||||||
if key_record is not None and key_record.presume_email_valid:
|
if key_record is not None and key_record.presume_email_valid:
|
||||||
# The user has a token created from the server command line;
|
# The user has a token created from the server command line;
|
||||||
|
@ -830,13 +860,21 @@ def create_realm(request: HttpRequest, creation_key: Optional[str] = None) -> Ht
|
||||||
"email": email,
|
"email": email,
|
||||||
"realm_name": realm_name,
|
"realm_name": realm_name,
|
||||||
"realm_type": realm_type,
|
"realm_type": realm_type,
|
||||||
|
"realm_default_language": realm_default_language,
|
||||||
"realm_subdomain": realm_subdomain,
|
"realm_subdomain": realm_subdomain,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
url = append_url_query_string(new_realm_send_confirm_url, query)
|
url = append_url_query_string(new_realm_send_confirm_url, query)
|
||||||
return HttpResponseRedirect(url)
|
return HttpResponseRedirect(url)
|
||||||
else:
|
else:
|
||||||
form = RealmCreationForm()
|
default_language_code = get_browser_language_code(request)
|
||||||
|
if default_language_code is None:
|
||||||
|
default_language_code = "en"
|
||||||
|
|
||||||
|
initial_data = {
|
||||||
|
"realm_default_language": default_language_code,
|
||||||
|
}
|
||||||
|
form = RealmCreationForm(initial=initial_data)
|
||||||
|
|
||||||
context = get_realm_create_form_context()
|
context = get_realm_create_form_context()
|
||||||
context.update(
|
context.update(
|
||||||
|
@ -868,6 +906,7 @@ def new_realm_send_confirm(
|
||||||
email: str = REQ("email"),
|
email: str = REQ("email"),
|
||||||
realm_name: str = REQ(str_validator=check_capped_string(Realm.MAX_REALM_NAME_LENGTH)),
|
realm_name: str = REQ(str_validator=check_capped_string(Realm.MAX_REALM_NAME_LENGTH)),
|
||||||
realm_type: int = REQ(json_validator=check_int_in(Realm.ORG_TYPE_IDS)),
|
realm_type: int = REQ(json_validator=check_int_in(Realm.ORG_TYPE_IDS)),
|
||||||
|
realm_default_language: str = REQ(str_validator=check_capped_string(MAX_LANGUAGE_ID_LENGTH)),
|
||||||
realm_subdomain: str = REQ(str_validator=check_capped_string(Realm.MAX_REALM_SUBDOMAIN_LENGTH)),
|
realm_subdomain: str = REQ(str_validator=check_capped_string(Realm.MAX_REALM_SUBDOMAIN_LENGTH)),
|
||||||
) -> HttpResponse:
|
) -> HttpResponse:
|
||||||
return TemplateResponse(
|
return TemplateResponse(
|
||||||
|
@ -880,6 +919,7 @@ def new_realm_send_confirm(
|
||||||
# creation.
|
# creation.
|
||||||
"new_realm_name": realm_name,
|
"new_realm_name": realm_name,
|
||||||
"realm_type": realm_type,
|
"realm_type": realm_type,
|
||||||
|
"realm_default_language": realm_default_language,
|
||||||
"realm_subdomain": realm_subdomain,
|
"realm_subdomain": realm_subdomain,
|
||||||
"realm_creation": True,
|
"realm_creation": True,
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in New Issue