settings: Create UI and backend for setting signups stream.

This commit is contained in:
Vishnu Ks 2017-10-20 14:55:04 +00:00 committed by Tim Abbott
parent 3d2c9c6098
commit 34689370cd
13 changed files with 296 additions and 12 deletions

View File

@ -28,9 +28,9 @@ casper.then(function () {
casper.test.info('Changing notifications stream to Verona by filtering with "verona"');
casper.click("#id_realm_notifications_stream > button.dropdown-toggle");
casper.waitUntilVisible('ul.dropdown-menu', function () {
casper.sendKeys('.dropdown-search > input[type=text]', 'verona');
casper.click(".dropdown-list-body li.stream_name");
casper.waitUntilVisible('#id_realm_notifications_stream ul.dropdown-menu', function () {
casper.sendKeys('#id_realm_notifications_stream .dropdown-search > input[type=text]', 'verona');
casper.click("#id_realm_notifications_stream .dropdown-list-body li.stream_name");
});
casper.waitUntilVisible('#admin-realm-notifications-stream-status', function () {
@ -49,6 +49,32 @@ casper.then(function () {
});
});
// Test changing signup notifications stream
casper.then(function () {
casper.test.info('Changing signup notifications stream to Verona by filtering with "verona"');
casper.click("#id_realm_signup_notifications_stream > button.dropdown-toggle");
casper.waitUntilVisible('#id_realm_signup_notifications_stream ul.dropdown-menu', function () {
casper.sendKeys('#id_realm_signup_notifications_stream .dropdown-search > input[type=text]', 'verona');
casper.click("#id_realm_signup_notifications_stream .dropdown-list-body li.stream_name");
});
casper.waitUntilVisible('#admin-realm-signup-notifications-stream-status', function () {
casper.test.assertSelectorHasText('#admin-realm-signup-notifications-stream-status',
'Signup notifications stream changed!');
casper.test.assertSelectorHasText('#realm_signup_notifications_stream_name', '#Verona');
});
});
casper.then(function () {
casper.click(".signup-notifications-stream-disable");
casper.waitUntilVisible('#admin-realm-signup-notifications-stream-status', function () {
casper.test.assertSelectorHasText('#admin-realm-signup-notifications-stream-status',
'Signup notifications stream disabled!');
casper.test.assertSelectorHasText('#realm_signup_notifications_stream_name', 'Disabled');
});
});
// Test permissions setting
casper.then(function () {
casper.click("li[data-section='organization-permissions']");

View File

@ -387,6 +387,31 @@ function test_disable_notifications_stream(disable_notifications_stream) {
'translated: Failed to change notifications stream!');
}
function test_disable_signup_notifications_stream(disable_signup_notifications_stream) {
var success_callback;
var error_callback;
channel.patch = function (req) {
assert.equal(req.url, '/json/realm');
assert.equal(req.data.signup_notifications_stream_id, '-1');
success_callback = req.success;
error_callback = req.error;
};
disable_signup_notifications_stream();
var response_data = {
signup_notifications_stream_id: -1,
};
success_callback(response_data);
assert.equal($('#admin-realm-signup-notifications-stream-status').val(),
'translated: Signup notifications stream disabled!');
error_callback({});
assert.equal($('#admin-realm-signup-notifications-stream-status').val(),
'translated: Failed to change signup notifications stream!');
}
function test_change_allow_subdomains(change_allow_subdomains) {
var ev = {
stopPropagation: noop,
@ -460,6 +485,7 @@ function test_change_allow_subdomains(change_allow_subdomains) {
$('#id_realm_allow_message_editing').change = set_callback('change_message_editing');
$('#submit-add-realm-domain').click = set_callback('add_realm_domain');
$('.notifications-stream-disable').click = set_callback('disable_notifications_stream');
$('.signup-notifications-stream-disable').click = set_callback('disable_signup_notifications_stream');
var submit_settings_form;
var submit_permissions_form;
@ -505,6 +531,7 @@ function test_change_allow_subdomains(change_allow_subdomains) {
test_change_invite_required(callbacks.change_invite_required);
test_change_message_editing(callbacks.change_message_editing);
test_disable_notifications_stream(callbacks.disable_notifications_stream);
test_disable_signup_notifications_stream(callbacks.disable_signup_notifications_stream);
test_change_allow_subdomains(change_allow_subdomains);
}());
@ -562,4 +589,19 @@ function test_change_allow_subdomains(change_allow_subdomains) {
settings_org.render_notifications_stream_ui();
assert.equal(elem.text(), 'translated: Disabled');
assert(elem.hasClass('text-warning'));
elem = $('#realm_signup_notifications_stream_name');
stream_data.get_sub_by_id = function (stream_id) {
assert.equal(stream_id, 75);
return { name: 'some_stream' };
};
settings_org.render_signup_notifications_stream_ui(75);
assert.equal(elem.text(), '#some_stream');
assert(!elem.hasClass('text-warning'));
stream_data.get_sub_by_id = noop;
settings_org.render_signup_notifications_stream_ui();
assert.equal(elem.text(), 'translated: Disabled');
assert(elem.hasClass('text-warning'));
}());

View File

@ -51,6 +51,7 @@ function _setup_page() {
realm_default_language: page_params.realm_default_language,
realm_waiting_period_threshold: page_params.realm_waiting_period_threshold,
realm_notifications_stream_id: page_params.realm_notifications_stream_id,
realm_signup_notifications_stream_id: page_params.realm_signup_notifications_stream_id,
is_admin: page_params.is_admin,
realm_icon_source: page_params.realm_icon_source,
realm_icon_url: page_params.realm_icon_url,

View File

@ -69,6 +69,7 @@ exports.dispatch_normal_event = function dispatch_normal_event(event) {
name: notifications.redraw_title,
name_changes_disabled: settings_org.toggle_name_change_display,
notifications_stream_id: noop,
signup_notifications_stream_id: noop,
restricted_to_domain: noop,
waiting_period_threshold: noop,
};
@ -83,6 +84,9 @@ exports.dispatch_normal_event = function dispatch_normal_event(event) {
} else if (event.property === 'notifications_stream_id') {
settings_org.render_notifications_stream_ui(
page_params.realm_notifications_stream_id);
} else if (event.property === 'signup_notifications_stream_id') {
settings_org.render_signup_notifications_stream_ui(
page_params.realm_signup_notifications_stream_id);
}
} else if (event.op === 'update_dict' && event.property === 'default') {
_.each(event.data, function (value, key) {
@ -193,6 +197,11 @@ exports.dispatch_normal_event = function dispatch_normal_event(event) {
settings_org.render_notifications_stream_ui(
page_params.realm_notifications_stream_id);
}
if (page_params.realm_signup_notifications_stream_id === stream.stream_id) {
page_params.realm_signup_notifications_stream_id = -1;
settings_org.render_signup_notifications_stream_ui(
page_params.realm_signup_notifications_stream_id);
}
});
}
break;

View File

@ -139,7 +139,7 @@ exports.populate_notifications_stream_dropdown = function (stream_list) {
var search_input = $("#id_realm_notifications_stream .dropdown-search > input[type=text]");
list_render(dropdown_list_body, stream_list, {
name: "admin-realm-dropdown-stream-list",
name: "admin-realm-notifications-stream-dropdown-list",
modifier: function (item) {
return templates.render("admin-realm-dropdown-stream-list", { stream: item });
},
@ -165,6 +165,48 @@ exports.populate_notifications_stream_dropdown = function (stream_list) {
});
};
exports.render_signup_notifications_stream_ui = function (stream_id) {
var elem = $('#realm_signup_notifications_stream_name');
var name = stream_data.maybe_get_stream_name(stream_id);
if (!name) {
elem.text(i18n.t("Disabled"));
elem.addClass("text-warning");
return;
}
// Happy path
elem.text('#' + name);
elem.removeClass('text-warning');
};
exports.populate_signup_notifications_stream_dropdown = function (stream_list) {
var dropdown_list_body = $("#id_realm_signup_notifications_stream .dropdown-list-body").expectOne();
var search_input = $("#id_realm_signup_notifications_stream .dropdown-search > input[type=text]");
list_render(dropdown_list_body, stream_list, {
name: "admin-realm-signup-notifications-stream-dropdown-list",
modifier: function (item) {
return templates.render("admin-realm-dropdown-stream-list", { stream: item });
},
filter: {
element: search_input,
callback: function (item, value) {
return item.name.toLowerCase().indexOf(value) >= 0;
},
},
}).init();
$("#id_realm_signup_notifications_stream .dropdown-search").click(function (e) {
e.stopPropagation();
});
$("#id_realm_signup_notifications_stream .dropdown-toggle").click(function () {
search_input.val("").trigger("input");
});
};
function property_type_status_element(element) {
return $("#admin-realm-" + element.split('_').join('-') + "-status").expectOne();
}
@ -176,9 +218,12 @@ function _set_up() {
// Populate notifications stream modal
if (page_params.is_admin) {
exports.populate_notifications_stream_dropdown(stream_data.get_streams_for_settings_page());
var streams = stream_data.get_streams_for_settings_page();
exports.populate_notifications_stream_dropdown(streams);
exports.populate_signup_notifications_stream_dropdown(streams);
}
exports.render_notifications_stream_ui(page_params.realm_notifications_stream_id);
exports.render_signup_notifications_stream_ui(page_params.realm_signup_notifications_stream_id);
// Populate realm domains
exports.populate_realm_domains(page_params.realm_domains);
@ -691,6 +736,52 @@ function _set_up() {
update_notifications_stream(-1);
});
var signup_notifications_stream_status = $("#admin-realm-signup-notifications-stream-status").expectOne();
function update_signup_notifications_stream(new_signup_notifications_stream_id) {
exports.render_signup_notifications_stream_ui(new_signup_notifications_stream_id);
signup_notifications_stream_status.hide();
var stringified_id = JSON.stringify(parseInt(new_signup_notifications_stream_id, 10));
var url = "/json/realm";
var data = {
signup_notifications_stream_id: stringified_id,
};
channel.patch({
url: url,
data: data,
success: function (response_data) {
if (response_data.signup_notifications_stream_id !== undefined) {
if (response_data.signup_notifications_stream_id < 0) {
ui_report.success(i18n.t("Signup notifications stream disabled!"), signup_notifications_stream_status);
} else {
ui_report.success(i18n.t("Signup notifications stream changed!"), signup_notifications_stream_status);
}
}
},
error: function (xhr) {
ui_report.error(i18n.t("Failed to change signup notifications stream!"), xhr, signup_notifications_stream_status);
},
});
}
dropdown_menu = $("#id_realm_signup_notifications_stream .dropdown-menu");
$("#id_realm_signup_notifications_stream .dropdown-list-body").on("click keypress", ".stream_name", function (e) {
if (e.type === "keypress") {
if (e.which === 13) {
dropdown_menu.dropdown("toggle");
} else {
return;
}
}
update_signup_notifications_stream($(this).attr("data-stream-id"));
});
$(".signup-notifications-stream-disable").click(function () {
update_signup_notifications_stream(-1);
});
function upload_realm_icon(file_input) {
var form_data = new FormData();

View File

@ -519,7 +519,8 @@ input[type=checkbox].inline-block {
text-align: left;
}
#realm_notifications_stream_label > button {
#realm_notifications_stream_label > button,
#realm_signup_notifications_stream_label > button {
margin: 0px 5px;
}
@ -1125,11 +1126,13 @@ input[type=checkbox].inline-block {
border-radius: 0px;
}
#id_realm_notifications_stream .dropdown-search > input[type=text] {
#id_realm_notifications_stream .dropdown-search > input[type=text],
#id_realm_signup_notifications_stream .dropdown-search > input[type=text] {
margin: 9px;
}
#id_realm_notifications_stream .dropdown-list-body {
#id_realm_notifications_stream .dropdown-list-body,
#id_realm_signup_notifications_stream .dropdown-list-body {
position: relative;
height: auto;
max-height: 200px;

View File

@ -1,6 +1,7 @@
<div id="organization-settings" data-name="organization-settings" class="settings-section">
<form class="form-horizontal admin-realm-form org-settings-form">
<div class="alert" id="admin-realm-notifications-stream-status"></div>
<div class="alert" id="admin-realm-signup-notifications-stream-status"></div>
<div class="alert" id="admin-realm-default-language-status"></div>
<div class="alert" id="admin-realm-inline-image-preview-status"></div>
@ -150,7 +151,7 @@
<div class="input-group">
<label for="realm_notifications_stream" id="realm_notifications_stream_label" class="inline-block"
title="{{t 'The stream to which new stream notifications go to.' }}">
{{t "Notifications stream:" }}
{{t "New stream notifications:" }}
<span class="dropup actual-dropdown-menu" id="id_realm_notifications_stream"
name="realm_notifications_stream" aria-labelledby="realm_notifications_stream_label">
<button class="button small rounded dropdown-toggle" data-toggle="dropdown">
@ -170,5 +171,28 @@
{{/if}}
</div>
<div class="input-group">
<label for="realm_signup_notifications_stream" id="realm_signup_notifications_stream_label" class="inline-block"
title="{{t 'The stream which new user signup notifications go to.' }}">
{{t "New user notifications:" }}
<span class="dropup actual-dropdown-menu" id="id_realm_signup_notifications_stream"
name="realm_signup_notifications_stream" aria-labelledby="realm_signup_notifications_stream_label">
<button class="button small rounded dropdown-toggle" data-toggle="dropdown">
<span id="realm_signup_notifications_stream_name"></span>
<i class="fa fa-pencil"></i>
</button>
<ul class="dropdown-menu" role="menu">
<li class="dropdown-search" role="presentation">
<input type="text" role="menuitem" placeholder="{{t 'Filter streams' }}" autofocus/>
</li>
<span class="dropdown-list-body"></span>
</ul>
</span>
</label>
{{#if is_admin }}
<a class="signup-notifications-stream-disable">{{t "[Disable]" }}</a>
{{/if}}
</div>
</form>
</div>

View File

@ -574,6 +574,18 @@ def do_set_realm_notifications_stream(realm, stream, stream_id):
)
send_event(event, active_user_ids(realm.id))
def do_set_realm_signup_notifications_stream(realm, stream, stream_id):
# type: (Realm, Stream, int) -> None
realm.signup_notifications_stream = stream
realm.save(update_fields=['signup_notifications_stream'])
event = dict(
type="realm",
op="update",
property="signup_notifications_stream_id",
value=stream_id
)
send_event(event, active_user_ids(realm.id))
def do_deactivate_realm(realm):
# type: (Realm) -> None
"""

View File

@ -172,6 +172,12 @@ def fetch_initial_state_data(user_profile, event_types, queue_id, client_gravata
else:
state['realm_notifications_stream_id'] = -1
if user_profile.realm.get_signup_notifications_stream():
signup_notifications_stream = user_profile.realm.get_signup_notifications_stream()
state['realm_signup_notifications_stream_id'] = signup_notifications_stream.id
else:
state['realm_signup_notifications_stream_id'] = -1
if want('realm_domains'):
state['realm_domains'] = get_realm_domains(user_profile.realm)

View File

@ -68,6 +68,7 @@ from zerver.lib.actions import (
do_set_realm_property,
do_set_user_display_setting,
do_set_realm_notifications_stream,
do_set_realm_signup_notifications_stream,
do_unmute_topic,
do_update_embedded_data,
do_update_message,
@ -1354,6 +1355,24 @@ class EventsRegisterTest(ZulipTestCase):
error = schema_checker('events[0]', events[0])
self.assert_on_error(error)
def test_change_realm_signup_notifications_stream(self) -> None:
schema_checker = self.check_events_dict([
('type', equals('realm')),
('op', equals('update')),
('property', equals('signup_notifications_stream_id')),
('value', check_int),
])
stream = get_stream("Rome", self.user_profile.realm)
for signup_notifications_stream, signup_notifications_stream_id in ((stream, stream.id), (None, -1)):
events = self.do_test(
lambda: do_set_realm_signup_notifications_stream(self.user_profile.realm,
signup_notifications_stream,
signup_notifications_stream_id))
error = schema_checker('events[0]', events[0])
self.assert_on_error(error)
def test_change_is_admin(self) -> None:
schema_checker = self.check_events_dict([
('type', equals('realm_user')),

View File

@ -138,6 +138,7 @@ class HomeTest(ZulipTestCase):
"realm_presence_disabled",
"realm_restricted_to_domain",
"realm_show_digest_email",
"realm_signup_notifications_stream_id",
"realm_uri",
"realm_user_groups",
"realm_users",
@ -387,6 +388,17 @@ class HomeTest(ZulipTestCase):
user.save()
return user
def test_signup_notifications_stream(self):
# type: () -> None
email = self.example_email("hamlet")
realm = get_realm('zulip')
realm.signup_notifications_stream = get_stream('Denmark', realm)
realm.save()
self.login(email)
result = self._get_home_page()
page_params = self._get_page_params(result)
self.assertEqual(page_params['realm_signup_notifications_stream_id'], get_stream('Denmark', realm).id)
@slow('creating users and loading home page')
def test_people(self) -> None:
hamlet = self.example_user('hamlet')

View File

@ -201,6 +201,32 @@ class RealmTest(ZulipTestCase):
do_deactivate_stream(notifications_stream)
self.assertIsNone(realm.get_notifications_stream())
def test_change_signup_notifications_stream(self) -> None:
# We need an admin user.
email = 'iago@zulip.com'
self.login(email)
disabled_signup_notifications_stream_id = -1
req = dict(signup_notifications_stream_id = ujson.dumps(disabled_signup_notifications_stream_id))
result = self.client_patch('/json/realm', req)
self.assert_json_success(result)
realm = get_realm('zulip')
self.assertEqual(realm.signup_notifications_stream, None)
new_signup_notifications_stream_id = 4
req = dict(signup_notifications_stream_id = ujson.dumps(new_signup_notifications_stream_id))
result = self.client_patch('/json/realm', req)
self.assert_json_success(result)
realm = get_realm('zulip')
self.assertEqual(realm.signup_notifications_stream.id, new_signup_notifications_stream_id)
invalid_signup_notifications_stream_id = 1234
req = dict(signup_notifications_stream_id = ujson.dumps(invalid_signup_notifications_stream_id))
result = self.client_patch('/json/realm', req)
self.assert_json_error(result, 'Invalid stream id')
realm = get_realm('zulip')
self.assertNotEqual(realm.signup_notifications_stream.id, invalid_signup_notifications_stream_id)
def test_get_default_signup_notifications_stream(self) -> None:
realm = get_realm("zulip")
verona = get_stream("verona", realm)

View File

@ -8,6 +8,7 @@ from zerver.lib.actions import (
do_set_realm_message_editing,
do_set_realm_authentication_methods,
do_set_realm_notifications_stream,
do_set_realm_signup_notifications_stream,
do_set_realm_property,
)
from zerver.lib.i18n import get_available_language_codes
@ -40,8 +41,9 @@ def update_realm(request, user_profile, name=REQ(validator=check_string, default
waiting_period_threshold=REQ(converter=to_non_negative_int, default=None),
authentication_methods=REQ(validator=check_dict([]), default=None),
notifications_stream_id=REQ(validator=check_int, default=None),
signup_notifications_stream_id=REQ(validator=check_int, default=None),
message_retention_days=REQ(converter=to_not_negative_int_or_none, default=None)):
# type: (HttpRequest, UserProfile, Optional[str], Optional[str], Optional[bool], Optional[bool], Optional[bool], Optional[bool], Optional[bool], Optional[bool], Optional[bool], Optional[bool], Optional[bool], Optional[bool], Optional[bool], Optional[bool], Optional[int], Optional[bool], Optional[str], Optional[int], Optional[Dict[Any,Any]], Optional[int], Optional[int]) -> 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[bool], Optional[bool], Optional[bool], Optional[bool], Optional[int], Optional[bool], Optional[str], Optional[int], Optional[Dict[Any,Any]], Optional[int], Optional[int], Optional[int]) -> HttpResponse
realm = user_profile.realm
# Additional validation/error checking beyond types go here, so
@ -92,8 +94,8 @@ def update_realm(request, user_profile, name=REQ(validator=check_string, default
message_content_edit_limit_seconds)
data['allow_message_editing'] = allow_message_editing
data['message_content_edit_limit_seconds'] = message_content_edit_limit_seconds
# Realm.notifications_stream is not a boolean, Text or integer field, and thus doesn't fit
# into the do_set_realm_property framework.
# Realm.notifications_stream and Realm.signup_notifications_stream are not boolean,
# Text or integer field, and thus doesn't fit into the do_set_realm_property framework.
if notifications_stream_id is not None:
if realm.notifications_stream is None or (realm.notifications_stream.id !=
notifications_stream_id):
@ -105,4 +107,15 @@ def update_realm(request, user_profile, name=REQ(validator=check_string, default
notifications_stream_id)
data['notifications_stream_id'] = notifications_stream_id
if signup_notifications_stream_id is not None:
if realm.signup_notifications_stream is None or (realm.signup_notifications_stream.id !=
signup_notifications_stream_id):
new_signup_notifications_stream = None
if signup_notifications_stream_id >= 0:
(new_signup_notifications_stream, recipient, sub) = access_stream_by_id(
user_profile, signup_notifications_stream_id)
do_set_realm_signup_notifications_stream(realm, new_signup_notifications_stream,
signup_notifications_stream_id)
data['signup_notifications_stream_id'] = signup_notifications_stream_id
return json_success(data)