Add organization description field to realm settings.

This adds an organization description field to the Realm model, as well as
an input field to the organization settings template. Added three tests.
Set the max length of the field to 100 characters.

Fixes #3962.
This commit is contained in:
Sarah Stringer
2017-03-18 19:19:44 +00:00
committed by Tim Abbott
parent 81f9de7cc8
commit aa880b0419
12 changed files with 114 additions and 3 deletions

View File

@@ -176,6 +176,10 @@ exports.toggle_email_change_display = function () {
$(".change_email_tooltip").toggle();
};
exports.update_realm_description = function (description) {
$('#id_realm_description').val(description);
};
exports.build_default_stream_table = function (streams_data) {
var self = {};
@@ -373,6 +377,7 @@ exports.populate_auth_methods = function (auth_methods) {
function _setup_page() {
var options = {
realm_name: page_params.realm_name,
realm_description: page_params.realm_description,
realm_restricted_to_domain: page_params.realm_restricted_to_domain,
realm_invite_required: page_params.realm_invite_required,
realm_invite_by_admins_only: page_params.realm_invite_by_admins_only,
@@ -614,6 +619,7 @@ function _setup_page() {
$(".administration").on("submit", "form.admin-realm-form", function (e) {
var name_status = $("#admin-realm-name-status").expectOne();
var description_status = $("#admin-realm-description-status").expectOne();
var restricted_to_domain_status = $("#admin-realm-restricted-to-domain-status").expectOne();
var invite_required_status = $("#admin-realm-invite-required-status").expectOne();
var invite_by_admins_only_status = $("#admin-realm-invite-by-admins-only-status").expectOne();
@@ -626,6 +632,7 @@ function _setup_page() {
var default_language_status = $("#admin-realm-default-language-status").expectOne();
var waiting_period_threshold_status = $("#admin-realm-waiting_period_threshold_status").expectOne();
name_status.hide();
description_status.hide();
restricted_to_domain_status.hide();
invite_required_status.hide();
invite_by_admins_only_status.hide();
@@ -642,6 +649,7 @@ function _setup_page() {
e.stopPropagation();
var new_name = $("#id_realm_name").val();
var new_description = $("#id_realm_description").val();
var new_restricted = $("#id_realm_restricted_to_domain").prop("checked");
var new_invite = $("#id_realm_invite_required").prop("checked");
var new_invite_by_admins_only = $("#id_realm_invite_by_admins_only").prop("checked");
@@ -673,6 +681,7 @@ function _setup_page() {
var url = "/json/realm";
var data = {
name: JSON.stringify(new_name),
description: JSON.stringify(new_description),
restricted_to_domain: JSON.stringify(new_restricted),
invite_required: JSON.stringify(new_invite),
invite_by_admins_only: JSON.stringify(new_invite_by_admins_only),
@@ -695,6 +704,9 @@ function _setup_page() {
if (response_data.name !== undefined) {
ui_report.success(i18n.t("Name changed!"), name_status);
}
if (response_data.description !== undefined) {
ui.report_success(i18n.t("Description changed!"), description_status);
}
if (response_data.restricted_to_domain !== undefined) {
if (response_data.restricted_to_domain) {
ui_report.success(i18n.t("New user e-mails now restricted to certain domains!"), restricted_to_domain_status);

View File

@@ -55,6 +55,9 @@ function dispatch_normal_event(event) {
if (event.op === 'update' && event.property === 'name') {
page_params.realm_name = event.value;
notifications.redraw_title();
} else if (event.op === 'update' && event.property === 'description') {
page_params.realm_description = event.value;
admin.update_realm_description(event.value);
} else if (event.op === 'update' && event.property === 'invite_required') {
page_params.realm_invite_required = event.value;
} else if (event.op === 'update' && event.property === 'invite_by_admins_only') {

View File

@@ -3,6 +3,7 @@
{{t "Organization settings" }}</div>
<form class="form-horizontal admin-realm-form">
<div class="alert" id="admin-realm-name-status"></div>
<div class="alert" id="admin-realm-description-status"></div>
<div class="alert" id="admin-realm-restricted-to-domain-status"></div>
<div class="alert" id="admin-realm-invite-required-status"></div>
<div class="alert" id="admin-realm-invite-by-admins-only-status"></div>
@@ -20,6 +21,11 @@
<input type="text" id="id_realm_name" name="realm_name" class="admin-realm-name"
value="{{ realm_name }}" />
</div>
<div class="input-group admin-realm">
<label for="realm_description">{{t "Your organization's description" }}</label>
<input type="text" id="id_realm_description" name="realm_description" class="admin-realm-description"
maxlength="100" value="{{ realm_description }}" />
</div>
<div class="input-group admin-restricted-to-domain">
<input type="checkbox" class="inline-block" id="id_realm_restricted_to_domain" name="realm_restricted_to_domain"
{{#if realm_restricted_to_domain}}checked="checked"{{/if}} />

View File

@@ -431,6 +431,18 @@ def do_set_realm_name(realm, name):
)
send_event(event, active_user_ids(realm))
def do_set_realm_description(realm, description):
# type: (Realm, Text) -> None
realm.description = description
realm.save(update_fields=['description'])
event = dict(
type='realm',
op='update',
property='description',
value=description,
)
send_event(event, active_user_ids(realm))
def do_set_realm_restricted_to_domain(realm, restricted):
# type: (Realm, bool) -> None
realm.restricted_to_domain = restricted

View File

@@ -93,6 +93,7 @@ def fetch_initial_state_data(user_profile, event_types, queue_id,
if want('realm'):
state['realm_name'] = user_profile.realm.name
state['realm_description'] = user_profile.realm.description
state['realm_restricted_to_domain'] = user_profile.realm.restricted_to_domain
state['realm_invite_required'] = user_profile.realm.invite_required
state['realm_invite_by_admins_only'] = user_profile.realm.invite_by_admins_only

View File

@@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.5 on 2017-03-19 19:06
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('zerver', '0062_default_timezone'),
]
operations = [
migrations.AddField(
model_name='realm',
name='description',
field=models.TextField(max_length=100, null=True),
),
]

View File

@@ -122,6 +122,7 @@ class Realm(ModelReprMixin, models.Model):
show_digest_email = models.BooleanField(default=True) # type: bool
name_changes_disabled = models.BooleanField(default=False) # type: bool
email_changes_disabled = models.BooleanField(default=False) # type: bool
description = models.TextField(max_length=100, null=True) # type: Optional[Text]
allow_message_editing = models.BooleanField(default=True) # type: bool
DEFAULT_MESSAGE_CONTENT_EDIT_LIMIT_SECONDS = 600 # if changed, also change in admin.js

View File

@@ -43,6 +43,7 @@ from zerver.lib.actions import (
do_set_muted_topics,
do_set_realm_create_stream_by_admins_only,
do_set_realm_name,
do_set_realm_description,
do_set_realm_restricted_to_domain,
do_set_realm_invite_required,
do_set_realm_invite_by_admins_only,
@@ -564,6 +565,18 @@ class EventsRegisterTest(ZulipTestCase):
error = schema_checker('events[0]', events[0])
self.assert_on_error(error)
def test_change_realm_description(self):
# type: () -> None
schema_checker = check_dict([
('type', equals('realm')),
('op', equals('update')),
('property', equals('description')),
('value', check_string),
])
events = self.do_test(lambda: do_set_realm_description(self.user_profile.realm, 'New Realm Description'))
error = schema_checker('events[0]', events[0])
self.assert_on_error(error)
def test_change_realm_restricted_to_domain(self):
# type: () -> None
schema_checker = check_dict([

View File

@@ -99,6 +99,7 @@ class HomeTest(ZulipTestCase):
"realm_create_stream_by_admins_only",
"realm_default_language",
"realm_default_streams",
"realm_description",
"realm_email_changes_disabled",
"realm_emoji",
"realm_filters",

View File

@@ -7,8 +7,13 @@ from django.http import HttpResponse
from mock import patch
from typing import Any, Dict, List, Text
from zerver.lib.actions import \
do_change_is_admin, do_set_realm_name, do_deactivate_realm, do_set_name_changes_disabled
from zerver.lib.actions import (
do_change_is_admin,
do_set_realm_name,
do_set_realm_description,
do_deactivate_realm,
do_set_name_changes_disabled,
)
from zerver.lib.test_classes import ZulipTestCase
from zerver.lib.test_helpers import tornado_redirected_to_list
@@ -48,6 +53,35 @@ class RealmTest(ZulipTestCase):
value = new_name,
))
def test_do_set_realm_description(self):
# type: () -> None
realm = get_realm('zulip')
new_description = 'zulip dev group'
events = [] # type: List[Dict[str, Any]]
with tornado_redirected_to_list(events):
do_set_realm_description(realm, new_description)
event = events[0]['event']
self.assertEqual(event, dict(
type='realm',
op='update',
property='description',
value=new_description,
))
def test_realm_description_length(self):
# type: () -> None
new_description = 'A' * 101
data = dict(description=ujson.dumps(new_description))
# create an admin user
email = 'iago@zulip.com'
self.login(email)
result = self.client_patch('/json/realm', data)
self.assert_json_error(result, 'Realm description cannot exceed 100 characters.')
realm = get_realm('zulip')
self.assertNotEqual(realm.description, new_description)
def test_update_realm_api(self):
# type: () -> None
new_name = 'Zulip: Worldwide Exporter of APIs'

View File

@@ -302,6 +302,7 @@ def home_real(request):
'realm_invite_required',
'realm_message_content_edit_limit_seconds',
'realm_name',
'realm_description',
'realm_name_changes_disabled',
'realm_restricted_to_domain',
'realm_waiting_period_threshold',

View File

@@ -8,6 +8,7 @@ from zerver.decorator import require_realm_admin, to_non_negative_int
from zerver.lib.actions import (
do_set_realm_create_stream_by_admins_only,
do_set_realm_name,
do_set_realm_description,
do_set_realm_invite_by_admins_only,
do_set_name_changes_disabled,
do_set_email_changes_disabled,
@@ -28,6 +29,7 @@ from zerver.models import UserProfile
@require_realm_admin
@has_request_variables
def update_realm(request, user_profile, name=REQ(validator=check_string, default=None),
description=REQ(validator=check_string, default=None),
restricted_to_domain=REQ(validator=check_bool, default=None),
invite_required=REQ(validator=check_bool, default=None),
invite_by_admins_only=REQ(validator=check_bool, default=None),
@@ -40,7 +42,7 @@ def update_realm(request, user_profile, name=REQ(validator=check_string, default
default_language=REQ(validator=check_string, default=None),
waiting_period_threshold=REQ(converter=to_non_negative_int, default=None),
authentication_methods=REQ(validator=check_dict([]), default=None)):
# type: (HttpRequest, UserProfile, Optional[str], Optional[bool], Optional[bool], Optional[bool], Optional[bool], Optional[bool], Optional[bool], Optional[bool], Optional[bool], Optional[int], Optional[str], Optional[int], Optional[dict]) -> HttpResponse
# type: (HttpRequest, UserProfile, Optional[str], Optional[str], Optional[bool], Optional[bool], Optional[bool], Optional[bool], Optional[bool], Optional[bool], Optional[bool], Optional[bool], Optional[int], Optional[str], Optional[int], Optional[dict]) -> 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,)))
@@ -49,6 +51,11 @@ def update_realm(request, user_profile, name=REQ(validator=check_string, default
if name is not None and realm.name != name:
do_set_realm_name(realm, name)
data['name'] = 'updated'
if description is not None and realm.description != description:
if len(description) > 100:
return json_error(_("Realm description cannot exceed 100 characters."))
do_set_realm_description(realm, description)
data['description'] = 'updated'
if restricted_to_domain is not None and realm.restricted_to_domain != restricted_to_domain:
do_set_realm_restricted_to_domain(realm, restricted_to_domain)
data['restricted_to_domain'] = restricted_to_domain