mirror of https://github.com/zulip/zulip.git
Add realm-level default language setting.
Adds a new field default language in the zerver_realm model. This realm level default language will be used as default language for newly created users. Realm level default language can be changed from the administration page. Fixes #1372.
This commit is contained in:
parent
7ec6a394fe
commit
2fef36f15a
|
@ -498,6 +498,18 @@ casper.then(function () {
|
|||
});
|
||||
});
|
||||
|
||||
casper.then(function () {
|
||||
casper.test.info("Changing realm default language");
|
||||
casper.evaluate(function () {
|
||||
$('#id_realm_default_language').val('de').change();
|
||||
});
|
||||
casper.click('form.admin-realm-form input.btn');
|
||||
});
|
||||
|
||||
casper.waitUntilVisible('#admin-realm-default-language-status', function () {
|
||||
casper.test.assertSelectorHasText('#admin-realm-default-language-status', 'Default language changed!');
|
||||
});
|
||||
|
||||
common.then_log_out();
|
||||
|
||||
casper.run(function () {
|
||||
|
|
|
@ -137,6 +137,10 @@ exports.populate_emoji = function (emoji_data) {
|
|||
loading.destroy_indicator($('#admin_page_emoji_loading_indicator'));
|
||||
};
|
||||
|
||||
exports.reset_realm_default_language = function () {
|
||||
$("#id_realm_default_language").val(page_params.realm_default_language);
|
||||
};
|
||||
|
||||
function _setup_page() {
|
||||
var options = {
|
||||
realm_name: page_params.realm_name,
|
||||
|
@ -146,7 +150,9 @@ function _setup_page() {
|
|||
realm_invite_by_admins_only: page_params.realm_invite_by_admins_only,
|
||||
realm_create_stream_by_admins_only: page_params.realm_create_stream_by_admins_only,
|
||||
realm_allow_message_editing: page_params.realm_allow_message_editing,
|
||||
realm_message_content_edit_limit_minutes: Math.ceil(page_params.realm_message_content_edit_limit_seconds / 60)
|
||||
realm_message_content_edit_limit_minutes: Math.ceil(page_params.realm_message_content_edit_limit_seconds / 60),
|
||||
language_list: page_params.language_list,
|
||||
realm_default_language: page_params.realm_default_language
|
||||
};
|
||||
var admin_tab = templates.render('admin_tab', options);
|
||||
$("#administration").html(admin_tab);
|
||||
|
@ -157,10 +163,13 @@ function _setup_page() {
|
|||
$("#admin-realm-invite-by-admins-only-status").expectOne().hide();
|
||||
$("#admin-realm-create-stream-by-admins-only-status").expectOne().hide();
|
||||
$("#admin-realm-message-editing-status").expectOne().hide();
|
||||
$("#admin-realm-default-language-status").expectOne().hide();
|
||||
$("#admin-emoji-status").expectOne().hide();
|
||||
$("#admin-emoji-name-status").expectOne().hide();
|
||||
$("#admin-emoji-url-status").expectOne().hide();
|
||||
|
||||
$("#id_realm_default_language").val(page_params.realm_default_language);
|
||||
|
||||
// create loading indicators
|
||||
loading.make_indicator($('#admin_page_users_loading_indicator'));
|
||||
loading.make_indicator($('#admin_page_bots_loading_indicator'));
|
||||
|
@ -360,12 +369,15 @@ function _setup_page() {
|
|||
var invite_by_admins_only_status = $("#admin-realm-invite-by-admins-only-status").expectOne();
|
||||
var create_stream_by_admins_only_status = $("#admin-realm-create-stream-by-admins-only-status").expectOne();
|
||||
var message_editing_status = $("#admin-realm-message-editing-status").expectOne();
|
||||
var default_language_status = $("#admin-realm-default-language-status").expectOne();
|
||||
|
||||
name_status.hide();
|
||||
restricted_to_domain_status.hide();
|
||||
invite_required_status.hide();
|
||||
invite_by_admins_only_status.hide();
|
||||
create_stream_by_admins_only_status.hide();
|
||||
message_editing_status.hide();
|
||||
default_language_status.hide();
|
||||
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
@ -377,6 +389,7 @@ function _setup_page() {
|
|||
var new_create_stream_by_admins_only = $("#id_realm_create_stream_by_admins_only").prop("checked");
|
||||
var new_allow_message_editing = $("#id_realm_allow_message_editing").prop("checked");
|
||||
var new_message_content_edit_limit_minutes = $("#id_realm_message_content_edit_limit_minutes").val();
|
||||
var new_default_language = $("#id_realm_default_language").val();
|
||||
|
||||
// If allow_message_editing is unchecked, message_content_edit_limit_minutes
|
||||
// is irrelevant. Hence if allow_message_editing is unchecked, and
|
||||
|
@ -398,7 +411,8 @@ function _setup_page() {
|
|||
invite_by_admins_only: JSON.stringify(new_invite_by_admins_only),
|
||||
create_stream_by_admins_only: JSON.stringify(new_create_stream_by_admins_only),
|
||||
allow_message_editing: JSON.stringify(new_allow_message_editing),
|
||||
message_content_edit_limit_seconds: JSON.stringify(parseInt(new_message_content_edit_limit_minutes, 10) * 60)
|
||||
message_content_edit_limit_seconds: JSON.stringify(parseInt(new_message_content_edit_limit_minutes, 10) * 60),
|
||||
default_language: JSON.stringify(new_default_language)
|
||||
};
|
||||
|
||||
channel.patch({
|
||||
|
@ -455,6 +469,11 @@ function _setup_page() {
|
|||
// in this function, so update the field just in case
|
||||
$("#id_realm_message_content_edit_limit_minutes").val(data_message_content_edit_limit_minutes);
|
||||
}
|
||||
if (response_data.default_language !== undefined) {
|
||||
if (response_data.default_language) {
|
||||
ui.report_success(i18n.t("Default language changed!"), default_language_status);
|
||||
}
|
||||
}
|
||||
},
|
||||
error: function (xhr, error) {
|
||||
ui.report_error(i18n.t("Failed!"), xhr, name_status);
|
||||
|
|
|
@ -99,6 +99,9 @@ function get_events_success(events) {
|
|||
$.each(event.data, function (key, value) {
|
||||
page_params['realm_' + key] = value;
|
||||
});
|
||||
} else if (event.op === 'update' && event.property === 'default_language') {
|
||||
page_params.realm_default_language = event.value;
|
||||
admin.reset_realm_default_language();
|
||||
}
|
||||
break;
|
||||
case 'realm_user':
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
<div class="alert" id="admin-realm-invite-by-admins-only-status"></div>
|
||||
<div class="alert" id="admin-realm-create-stream-by-admins-only-status"></div>
|
||||
<div class="alert" id="admin-realm-message-editing-status"></div>
|
||||
<div class="alert" id="admin-realm-default-language-status"></div>
|
||||
<label for="realm_name" class="control-label">{{t "Your organization's name" }}</label>
|
||||
<div class="controls">
|
||||
<input type="text" id="id_realm_name" name="realm_name" class="admin-realm-name"
|
||||
|
@ -116,6 +117,16 @@
|
|||
{{#unless realm_allow_message_editing}}disabled="disabled"{{/unless}} />
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label for="realm_default_language" class="control-label">{{t "Default Language" }}:</label>
|
||||
<div class="controls">
|
||||
<select name="realm_default_language" id="id_realm_default_language">
|
||||
{{#each language_list}}
|
||||
<option value='{{this.code}}'>{{this.name}}</option>
|
||||
{{/each}}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="controls organization-submission">
|
||||
<input type="submit" class="btn btn-big btn-primary" value="{{t 'Save changes' }}" />
|
||||
</div>
|
||||
|
|
|
@ -427,6 +427,25 @@ def do_set_realm_message_editing(realm, allow_message_editing, message_content_e
|
|||
)
|
||||
send_event(event, active_user_ids(realm))
|
||||
|
||||
def do_set_realm_default_language(realm, default_language):
|
||||
# type: (Realm, text_type) -> None
|
||||
|
||||
if default_language == 'zh_CN':
|
||||
# NB: remove this once we upgrade to Django 1.9
|
||||
# zh-cn and zh-tw will be replaced by zh-hans and zh-hant in
|
||||
# Django 1.9
|
||||
default_language= 'zh_HANS'
|
||||
|
||||
realm.default_language = default_language
|
||||
realm.save(update_fields=['default_language'])
|
||||
event = dict(
|
||||
type="realm",
|
||||
op="update",
|
||||
property="default_language",
|
||||
value=default_language
|
||||
)
|
||||
send_event(event, active_user_ids(realm))
|
||||
|
||||
def do_deactivate_realm(realm):
|
||||
# type: (Realm) -> None
|
||||
"""
|
||||
|
@ -2710,6 +2729,7 @@ def fetch_initial_state_data(user_profile, event_types, queue_id):
|
|||
state['realm_create_stream_by_admins_only'] = user_profile.realm.create_stream_by_admins_only
|
||||
state['realm_allow_message_editing'] = user_profile.realm.allow_message_editing
|
||||
state['realm_message_content_edit_limit_seconds'] = user_profile.realm.message_content_edit_limit_seconds
|
||||
state['realm_default_language'] = user_profile.realm.default_language
|
||||
|
||||
if want('realm_domain'):
|
||||
state['realm_domain'] = user_profile.realm.domain
|
||||
|
|
|
@ -39,7 +39,8 @@ def create_user_profile(realm, email, password, active, bot_type, full_name,
|
|||
pointer=-1, is_bot=bool(bot_type), bot_type=bot_type,
|
||||
is_mirror_dummy=is_mirror_dummy,
|
||||
enable_stream_desktop_notifications=enable_stream_desktop_notifications,
|
||||
onboarding_steps=ujson.dumps([]))
|
||||
onboarding_steps=ujson.dumps([]),
|
||||
default_language=realm.default_language)
|
||||
if bot_owner is not None:
|
||||
# `user_profile.bot_owner = bot_owner` doesn't work on python 3.4
|
||||
user_profile.bot_owner_id = bot_owner.id
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('zerver', '0026_delete_mituser'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='realm',
|
||||
name='default_language',
|
||||
field=models.CharField(default='en', max_length=50),
|
||||
),
|
||||
]
|
|
@ -153,6 +153,7 @@ class Realm(ModelReprMixin, models.Model):
|
|||
date_created = models.DateTimeField(default=timezone.now) # type: datetime.datetime
|
||||
notifications_stream = models.ForeignKey('Stream', related_name='+', null=True, blank=True) # type: Optional[Stream]
|
||||
deactivated = models.BooleanField(default=False) # type: bool
|
||||
default_language = models.CharField(default=u'en', max_length=MAX_LANGUAGE_ID_LENGTH) # type: text_type
|
||||
|
||||
DEFAULT_NOTIFICATION_STREAM_NAME = u'announce'
|
||||
|
||||
|
|
|
@ -41,6 +41,7 @@ from zerver.lib.actions import (
|
|||
do_set_realm_invite_required,
|
||||
do_set_realm_invite_by_admins_only,
|
||||
do_set_realm_message_editing,
|
||||
do_set_realm_default_language,
|
||||
do_update_message,
|
||||
do_update_pointer,
|
||||
do_change_twenty_four_hour_time,
|
||||
|
@ -478,6 +479,18 @@ class EventsRegisterTest(AuthedTestCase):
|
|||
error = schema_checker('events[0]', events[0])
|
||||
self.assert_on_error(error)
|
||||
|
||||
def test_change_realm_default_language(self):
|
||||
# type: () -> None
|
||||
schema_checker = check_dict([
|
||||
('type', equals('realm')),
|
||||
('op', equals('update')),
|
||||
('property', equals('default_language')),
|
||||
('value', check_string),
|
||||
])
|
||||
events = self.do_test(lambda: do_set_realm_default_language(self.user_profile.realm, 'de'))
|
||||
error = schema_checker('events[0]', events[0])
|
||||
self.assert_on_error(error)
|
||||
|
||||
def test_change_realm_create_stream_by_admins_only(self):
|
||||
# type: () -> None
|
||||
schema_checker = check_dict([
|
||||
|
|
|
@ -18,6 +18,7 @@ from zerver.lib.actions import (
|
|||
set_default_streams,
|
||||
)
|
||||
|
||||
from zerver.lib.actions import do_set_realm_default_language
|
||||
from zerver.lib.digest import send_digest_email
|
||||
from zerver.lib.notifications import enqueue_welcome_emails, one_click_unsubscribe_link
|
||||
from zerver.lib.test_helpers import AuthedTestCase, find_key_by_email, queries_captured
|
||||
|
@ -664,3 +665,45 @@ class RealmCreationTest(AuthedTestCase):
|
|||
|
||||
result = self.client_get(result["Location"])
|
||||
self.assert_in_response("You're the first one here!", result)
|
||||
|
||||
class UserSignUpTest(AuthedTestCase):
|
||||
|
||||
def test_user_default_language(self):
|
||||
"""
|
||||
Check if the default language of new user is the default language
|
||||
of the realm.
|
||||
"""
|
||||
username = "newguy"
|
||||
email = "newguy@zulip.com"
|
||||
domain = "zulip.com"
|
||||
password = "newpassword"
|
||||
realm = get_realm(domain)
|
||||
do_set_realm_default_language(realm, "de")
|
||||
|
||||
result = self.client_post('/accounts/home/', {'email': email})
|
||||
self.assertEquals(result.status_code, 302)
|
||||
self.assertTrue(result["Location"].endswith(
|
||||
"/accounts/send_confirm/%s@%s" % (username, domain)))
|
||||
result = self.client_get(result["Location"])
|
||||
self.assert_in_response("Check your email so we can get started.", result)
|
||||
|
||||
# Visit the confirmation link.
|
||||
from django.core.mail import outbox
|
||||
for message in reversed(outbox):
|
||||
if email in message.to:
|
||||
confirmation_link_pattern = re.compile(settings.EXTERNAL_HOST + "(\S+)>")
|
||||
confirmation_url = confirmation_link_pattern.search(
|
||||
message.body).groups()[0]
|
||||
break
|
||||
else:
|
||||
raise ValueError("Couldn't find a confirmation email.")
|
||||
|
||||
result = self.client_get(confirmation_url)
|
||||
self.assertEquals(result.status_code, 200)
|
||||
# Pick a password and agree to the ToS.
|
||||
result = self.submit_reg_form_for_user(username, password, domain)
|
||||
self.assertEquals(result.status_code, 302)
|
||||
|
||||
user_profile = get_user_profile_by_email(email)
|
||||
self.assertEqual(user_profile.default_language, realm.default_language)
|
||||
outbox.pop()
|
||||
|
|
|
@ -166,6 +166,41 @@ class RealmTest(AuthedTestCase):
|
|||
user = get_user_profile_by_email('hamlet@zulip.com')
|
||||
self.assertTrue(user.realm.deactivated)
|
||||
|
||||
def test_do_set_realm_default_language(self):
|
||||
# type: () -> None
|
||||
new_lang = "de"
|
||||
realm = get_realm('zulip.com')
|
||||
self.assertNotEqual(realm.default_language, new_lang)
|
||||
# we need an admin user.
|
||||
email = 'iago@zulip.com'
|
||||
self.login(email)
|
||||
|
||||
req = dict(default_language=ujson.dumps(new_lang))
|
||||
result = self.client_patch('/json/realm', req)
|
||||
self.assert_json_success(result)
|
||||
realm = get_realm('zulip.com')
|
||||
self.assertEqual(realm.default_language, new_lang)
|
||||
|
||||
# Test setting zh_CN, we set zh_HANS instead of zh_CN in db
|
||||
chinese = "zh_CN"
|
||||
simplified_chinese = "zh_HANS"
|
||||
req = dict(default_language=ujson.dumps(chinese))
|
||||
result = self.client_patch('/json/realm', req)
|
||||
self.assert_json_success(result)
|
||||
realm = get_realm('zulip.com')
|
||||
self.assertEqual(realm.default_language, simplified_chinese)
|
||||
|
||||
# Test to make sure that when invalid languages are passed
|
||||
# as the default realm language, correct validation error is
|
||||
# raised and the invalid language is not saved in db
|
||||
invalid_lang = "invalid_lang"
|
||||
req = dict(default_language=ujson.dumps(invalid_lang))
|
||||
result = self.client_patch('/json/realm', req)
|
||||
self.assert_json_error(result, "Invalid language '%s'" % (invalid_lang,))
|
||||
realm = get_realm('zulip.com')
|
||||
self.assertNotEqual(realm.default_language, invalid_lang)
|
||||
|
||||
|
||||
class PermissionTest(AuthedTestCase):
|
||||
def test_get_admin_users(self):
|
||||
# type: () -> None
|
||||
|
@ -1819,6 +1854,7 @@ class HomeTest(AuthedTestCase):
|
|||
"prompt_for_invites",
|
||||
"realm_allow_message_editing",
|
||||
"realm_create_stream_by_admins_only",
|
||||
"realm_default_language",
|
||||
"realm_default_streams",
|
||||
"realm_emoji",
|
||||
"realm_filters",
|
||||
|
|
|
@ -942,6 +942,7 @@ def home(request):
|
|||
realm_allow_message_editing = register_ret['realm_allow_message_editing'],
|
||||
realm_message_content_edit_limit_seconds = register_ret['realm_message_content_edit_limit_seconds'],
|
||||
realm_restricted_to_domain = register_ret['realm_restricted_to_domain'],
|
||||
realm_default_language = register_ret['realm_default_language'],
|
||||
enter_sends = user_profile.enter_sends,
|
||||
left_side_userlist = register_ret['left_side_userlist'],
|
||||
default_language = register_ret['default_language'],
|
||||
|
@ -992,6 +993,7 @@ def home(request):
|
|||
presence_disabled = user_profile.realm.presence_disabled,
|
||||
is_zephyr_mirror_realm = user_profile.realm.is_zephyr_mirror_realm,
|
||||
)
|
||||
|
||||
if narrow_stream is not None:
|
||||
# In narrow_stream context, initial pointer is just latest message
|
||||
recipient = get_recipient(Recipient.STREAM, narrow_stream.id)
|
||||
|
|
|
@ -3,6 +3,8 @@ from __future__ import absolute_import
|
|||
from typing import Any, Optional
|
||||
|
||||
from django.http import HttpRequest, HttpResponse
|
||||
from django.utils.translation import ugettext as _
|
||||
|
||||
from zerver.decorator import require_realm_admin, to_non_negative_int
|
||||
from zerver.lib.actions import (
|
||||
do_set_realm_create_stream_by_admins_only,
|
||||
|
@ -11,8 +13,10 @@ from zerver.lib.actions import (
|
|||
do_set_realm_invite_required,
|
||||
do_set_realm_message_editing,
|
||||
do_set_realm_restricted_to_domain,
|
||||
do_set_realm_default_language,
|
||||
)
|
||||
from zerver.lib.request import has_request_variables, REQ
|
||||
from zerver.lib.i18n import get_available_language_codes
|
||||
from zerver.lib.request import has_request_variables, REQ, JsonableError
|
||||
from zerver.lib.response import json_success, json_error
|
||||
from zerver.lib.validator import check_string, check_list, check_bool
|
||||
from zerver.models import UserProfile
|
||||
|
@ -25,8 +29,13 @@ def update_realm(request, user_profile, name=REQ(validator=check_string, default
|
|||
invite_by_admins_only=REQ(validator=check_bool, default=None),
|
||||
create_stream_by_admins_only=REQ(validator=check_bool, default=None),
|
||||
allow_message_editing=REQ(validator=check_bool, default=None),
|
||||
message_content_edit_limit_seconds=REQ(converter=to_non_negative_int, default=None)):
|
||||
# type: (HttpRequest, UserProfile, Optional[str], Optional[bool], Optional[bool], Optional[bool], Optional[bool], Optional[bool], Optional[int]) -> HttpResponse
|
||||
message_content_edit_limit_seconds=REQ(converter=to_non_negative_int, default=None),
|
||||
default_language=REQ(validator=check_string, default=None)):
|
||||
# type: (HttpRequest, UserProfile, Optional[str], Optional[bool], Optional[bool], Optional[bool], Optional[bool], Optional[bool], Optional[int], Optional[str]) -> HttpResponse
|
||||
# Validation for default_language
|
||||
if default_language is not None and default_language not in get_available_language_codes():
|
||||
raise JsonableError(_("Invalid language '%s'" % (default_language,)))
|
||||
|
||||
realm = user_profile.realm
|
||||
data = {} # type: Dict[str, Any]
|
||||
if name is not None and realm.name != name:
|
||||
|
@ -54,4 +63,7 @@ def update_realm(request, user_profile, name=REQ(validator=check_string, default
|
|||
do_set_realm_message_editing(realm, allow_message_editing, message_content_edit_limit_seconds)
|
||||
data['allow_message_editing'] = allow_message_editing
|
||||
data['message_content_edit_limit_seconds'] = message_content_edit_limit_seconds
|
||||
if default_language is not None and realm.default_language != default_language:
|
||||
do_set_realm_default_language(realm, default_language)
|
||||
data['default_language'] = default_language
|
||||
return json_success(data)
|
||||
|
|
Loading…
Reference in New Issue