invites: Frontend changes for adding the new realm setting.

This commit does the changes in frontend required
for adding the new setting `Who can create multiuse invite link.`

Fixes #15159.
This commit is contained in:
Ujjawal Modi 2023-08-03 19:36:40 +05:30 committed by Tim Abbott
parent 21b1298c1d
commit 9a96d19315
21 changed files with 172 additions and 24 deletions

View File

@ -57,8 +57,6 @@ permission to invite users.
## Create a reusable invitation link
{!admin-only.md!}
{start_tabs}
{!invite-users.md!}

View File

@ -16,9 +16,8 @@ account and how users access their accounts:
to sign up (default), or you can [allow anyone to
join](#set-whether-invitations-are-required-to-join) without an invitation.
* You can [restrict who can invite users](#change-who-can-send-invitations) to
your organization. To protect your organization, creating *reusable* invite
links is always limited to administrators.
* You can [restrict the ability to invite new users](#change-who-can-send-invitations) to
join your Zulip organzation to specific [roles](/help/roles-and-permissions).
Regardless of whether invitations are required, you can:
@ -49,19 +48,13 @@ Regardless of whether invitations are required, you can:
## Change who can send invitations
{!owner-only.md!}
You can restrict the ability to invite new users to join your Zulip organization
to specific [roles](/help/roles-and-permissions). To protect your organization,
while permission to send out individual email invitations is configurable, creating
*reusable* invitation links is always limited to administrators.
{start_tabs}
{settings_tab|organization-permissions}
1. Under **Joining the organization**, configure
**Who can send email invitations to new users**.
**Who can send email invitations to new users** and
**Who can create reusable invitation links**.
{!save-changes.md!}

View File

@ -160,6 +160,7 @@ export function build_page() {
email_address_visibility_values: settings_config.email_address_visibility_values,
waiting_period_threshold_dropdown_values:
settings_config.waiting_period_threshold_dropdown_values,
can_create_multiuse_invite: settings_data.user_can_create_multiuse_invite(),
can_invite_users_by_email: settings_data.user_can_invite_users_by_email(),
realm_invite_required: page_params.realm_invite_required,
can_edit_user_groups: settings_data.user_can_edit_user_groups(),

View File

@ -126,6 +126,7 @@ export function initialize(): void {
server_needs_upgrade: page_params.server_needs_upgrade,
version_display_string: version_display_string(),
apps_page_url: page_params.apps_page_url,
can_create_multiuse_invite: settings_data.user_can_create_multiuse_invite(),
can_invite_users_by_email: settings_data.user_can_invite_users_by_email(),
corporate_enabled: page_params.corporate_enabled,
is_guest: page_params.is_guest,

View File

@ -15,6 +15,15 @@ const group_permission_config_dict = new Map<string, GroupPermissionSetting>([
allow_nobody_group: false,
},
],
[
"create_multiuse_invite_group",
{
require_system_group: true,
allow_internet_group: false,
allow_owners_group: false,
allow_nobody_group: true,
},
],
]);
export function get_group_permission_setting_config(

View File

@ -273,7 +273,7 @@ function open_invite_user_modal(e) {
$("#invite-user-modal .dialog_submit_button").prop("disabled", true);
$("#email_invite_radio").prop("checked", true);
if (!page_params.is_admin) {
if (!settings_data.user_can_create_multiuse_invite()) {
$("#generate_multiuse_invite_radio").prop("disabled", true);
$("#generate_multiuse_invite_radio_container").addClass("control-label-disabled");
$("#generate_multiuse_invite_radio_container").addClass("disabled_setting_tooltip");
@ -359,6 +359,16 @@ function open_invite_user_modal(e) {
if (!user_has_email_set) {
$("#invite-user-form :input").prop("disabled", !user_has_email_set);
}
if (!settings_data.user_can_invite_users_by_email()) {
$("#email_invite_radio").prop("disabled", true);
$("#email_invite_radio_container").addClass(
"control-label-disabled disabled_setting_tooltip",
);
$("#generate_multiuse_invite_radio").prop("checked", true);
$("#generate_multiuse_invite_radio").trigger("change");
}
}
function invite_users() {

View File

@ -25,6 +25,7 @@ export const page_params: {
promote_sponsoring_zulip: boolean;
realm_add_custom_emoji_policy: number;
realm_avatar_changes_disabled: boolean;
realm_create_multiuse_invite_group: number;
realm_create_private_stream_policy: number;
realm_create_public_stream_policy: number;
realm_create_web_public_stream_policy: number;

View File

@ -197,6 +197,7 @@ export function dispatch_normal_event(event) {
user_group_edit_policy: noop,
avatar_changes_disabled: settings_account.update_avatar_change_display,
bot_creation_policy: settings_bots.update_bot_permissions_ui,
create_multiuse_invite_group: noop,
create_public_stream_policy: noop,
create_private_stream_policy: noop,
create_web_public_stream_policy: noop,
@ -279,6 +280,12 @@ export function dispatch_normal_event(event) {
settings_org.sync_realm_settings(key);
}
if (key === "create_multiuse_invite_group") {
settings_invites.update_invite_user_panel();
ui_init.update_invite_user_option();
gear_menu.initialize();
}
if (key === "edit_topic_policy") {
message_live_update.rerender_messages_view();
}

View File

@ -1,5 +1,6 @@
import {page_params} from "./page_params";
import * as settings_config from "./settings_config";
import * as user_groups from "./user_groups";
import {user_settings} from "./user_settings";
let user_join_date: Date;
@ -141,6 +142,16 @@ export function user_can_invite_users_by_email(): boolean {
return user_has_permission(page_params.realm_invite_to_realm_policy);
}
export function user_can_create_multiuse_invite(): boolean {
if (!page_params.user_id) {
return false;
}
return user_groups.is_user_in_group(
page_params.realm_create_multiuse_invite_group,
page_params.user_id,
);
}
export function user_can_subscribe_other_users(): boolean {
return user_has_permission(page_params.realm_invite_to_stream_policy);
}

View File

@ -296,7 +296,10 @@ export function update_invite_users_setting_tip() {
export function update_invite_user_panel() {
update_invite_users_setting_tip();
if (!settings_data.user_can_invite_users_by_email()) {
if (
!settings_data.user_can_invite_users_by_email() &&
!settings_data.user_can_create_multiuse_invite()
) {
$("#admin-invites-list .invite-user-link").hide();
} else {
$("#admin-invites-list .invite-user-link").show();

View File

@ -28,6 +28,7 @@ import * as stream_data from "./stream_data";
import * as stream_edit from "./stream_edit";
import * as stream_settings_data from "./stream_settings_data";
import * as ui_report from "./ui_report";
import * as user_groups from "./user_groups";
const meta = {
loaded: false,
@ -53,7 +54,7 @@ export function maybe_disable_widgets() {
$(".deactivate_realm_button").prop("disabled", true);
$("#deactivate_realm_button_container").addClass("disabled_setting_tooltip");
$("#org-message-retention").find("input, select").prop("disabled", true);
$("#org-join-settings").find("input, select").prop("disabled", true);
$("#org-join-settings").find("input, select, button").prop("disabled", true);
$("#id_realm_invite_required_label").parent().addClass("control-label-disabled");
return;
}
@ -608,6 +609,7 @@ function update_dependent_subsettings(property_name) {
export let default_code_language_widget = null;
export let notifications_stream_widget = null;
export let signup_notifications_stream_widget = null;
export let create_multiuse_invite_group_widget = null;
export function get_widget_for_dropdown_list_settings(property_name) {
switch (property_name) {
@ -617,6 +619,8 @@ export function get_widget_for_dropdown_list_settings(property_name) {
return signup_notifications_stream_widget;
case "realm_default_code_block_language":
return default_code_language_widget;
case "realm_create_multiuse_invite_group":
return create_multiuse_invite_group_widget;
case "can_remove_subscribers_group":
return stream_edit.can_remove_subscribers_group_widget;
default:
@ -655,6 +659,7 @@ export function discard_property_element_changes(elem, for_realm_default_setting
case "realm_signup_notifications_stream_id":
case "realm_default_code_block_language":
case "can_remove_subscribers_group":
case "realm_create_multiuse_invite_group":
set_dropdown_list_widget_setting_value(property_name, property_value);
break;
case "realm_default_language":
@ -971,6 +976,7 @@ export function check_property_changed(elem, for_realm_default_settings, sub) {
case "realm_signup_notifications_stream_id":
case "realm_default_code_block_language":
case "can_remove_subscribers_group":
case "realm_create_multiuse_invite_group":
proposed_val = get_dropdown_list_widget_setting_value($elem);
break;
case "email_notifications_batching_period_seconds":
@ -1157,6 +1163,31 @@ export function init_dropdown_widgets() {
},
});
default_code_language_widget.setup();
create_multiuse_invite_group_widget = new dropdown_widget.DropdownWidget({
widget_name: "realm_create_multiuse_invite_group",
get_options: () =>
user_groups.get_realm_user_groups_for_dropdown_list_widget(
"create_multiuse_invite_group",
),
$events_container: $("#settings_overlay_container #organization-permissions"),
item_click_callback(event, dropdown) {
dropdown.hide();
event.preventDefault();
event.stopPropagation();
create_multiuse_invite_group_widget.render();
save_discard_widget_status_handler($("#org-join-settings"));
},
tippy_props: {
placement: "bottom-start",
},
default_id: page_params.realm_create_multiuse_invite_group,
unique_id_type: dropdown_widget.DATA_TYPES.NUMBER,
on_mount_callback(dropdown) {
$(dropdown.popper).css("min-width", "300px");
},
});
create_multiuse_invite_group_widget.setup();
}
function check_maximum_valid_value($custom_input_elem, property_name) {

View File

@ -373,6 +373,18 @@ export function initialize() {
},
});
delegate("body", {
target: ["#email_invite_radio_container.disabled_setting_tooltip"],
content: $t({
defaultMessage:
"You do not have permissions to send email invitations in this organization.",
}),
appendTo: () => document.body,
onHidden(instance) {
instance.destroy();
},
});
delegate("body", {
target: "#pm_tooltip_container",
onShow(instance) {

View File

@ -190,7 +190,10 @@ function initialize_left_sidebar() {
}
export function update_invite_user_option() {
if (!settings_data.user_can_invite_users_by_email()) {
if (
!settings_data.user_can_invite_users_by_email() &&
!settings_data.user_can_create_multiuse_invite()
) {
$("#right-sidebar .invite-user-link").hide();
} else {
$("#right-sidebar .invite-user-link").show();

View File

@ -420,7 +420,8 @@
/* these are converting grey things to "new grey" */
:disabled,
input:not([type="radio"]):read-only,
textarea:read-only {
textarea:read-only,
#org-join-settings .dropdown-widget-button:disabled {
color: inherit;
opacity: 0.5;
}
@ -479,7 +480,8 @@
.pill-container,
.user-status-content-wrapper,
#custom-expiration-time-input,
#searchbox #search_query {
#searchbox #search_query,
#org-join-settings .dropdown-widget-button {
background-color: hsl(0deg 0% 0% / 20%);
border-color: hsl(0deg 0% 0% / 60%);
color: inherit;

View File

@ -775,6 +775,24 @@ input[type="checkbox"] {
margin: 20px 0 0;
}
#org-join-settings {
.dropdown-widget-button {
width: 325px;
color: hsl(0deg 0% 33%);
& i {
font-size: 10px;
margin-right: -3px;
}
&:disabled {
cursor: not-allowed;
background-color: hsl(0deg 0% 93%);
opacity: 0.7;
}
}
}
.progressive-table-wrapper {
position: relative;
max-height: calc(95vh - 220px);

View File

@ -2521,6 +2521,10 @@ select.invite-as {
.invite_type_radio_section {
margin: 2px 2px 2px 5px;
& div {
width: fit-content;
}
& input[type="radio"] {
cursor: pointer;
@ -2535,10 +2539,6 @@ select.invite-as {
}
}
#generate_multiuse_invite_radio_container {
width: fit-content;
}
#custom-expiration-time-input {
width: 5ch;
margin-right: 15px;

View File

@ -155,7 +155,7 @@
</li>
{{/if}}
<li class="divider hidden-for-spectators" role="presentation"></li>
{{#if can_invite_users_by_email}}
{{#if (or can_invite_users_by_email can_create_multiuse_invite)}}
<li role="presentation">
<a class="invite-user-link" role="menuitem">
<i class="fa fa-user-plus" aria-hidden="true"></i> {{t 'Invite users' }}

View File

@ -23,6 +23,11 @@
</select>
</div>
{{> ../dropdown_widget_with_label
widget_name="realm_create_multiuse_invite_group"
label=(t 'Who can create reusable invitation links')
value_type="number"}}
<div class="input-group">
<label for="realm_org_join_restrictions" class="dropdown-title">{{t "Restrict email domains of new users?" }}</label>
<select name="realm_org_join_restrictions" id="id_realm_org_join_restrictions" class="prop-element settings_select bootstrap-focus-style">

View File

@ -544,11 +544,13 @@ run_test("realm settings", ({override}) => {
assert_same(update_called, true);
event = event_fixtures.realm__update_dict__default;
page_params.realm_create_multiuse_invite_group = 1;
page_params.realm_allow_message_editing = false;
page_params.realm_message_content_edit_limit_seconds = 0;
page_params.realm_edit_topic_policy = 3;
override(settings_org, "populate_auth_methods", noop);
dispatch(event);
assert_same(page_params.realm_create_multiuse_invite_group, 3);
assert_same(page_params.realm_allow_message_editing, true);
assert_same(page_params.realm_message_content_edit_limit_seconds, 5);
assert_same(page_params.realm_edit_topic_policy, 4);

View File

@ -374,6 +374,7 @@ exports.fixtures = {
allow_message_editing: true,
message_content_edit_limit_seconds: 5,
edit_topic_policy: 4,
create_multiuse_invite_group: 3,
authentication_methods: {
Google: true,
},

View File

@ -8,6 +8,7 @@ const {page_params, user_settings} = require("./lib/zpage_params");
const settings_data = zrequire("settings_data");
const settings_config = zrequire("settings_config");
const user_groups = zrequire("user_groups");
/*
Some methods in settings_data are fairly
@ -331,3 +332,42 @@ run_test("user_email_not_configured", () => {
page_params.delivery_email = "name@example.com";
assert.equal(user_email_not_configured(), false);
});
run_test("user_can_create_multiuse_invite", () => {
const admin_user_id = 1;
const moderator_user_id = 2;
const member_user_id = 3;
const admins = {
name: "Admins",
id: 1,
members: new Set([admin_user_id]),
is_system_group: true,
direct_subgroup_ids: new Set([]),
};
const moderators = {
name: "Moderators",
id: 2,
members: new Set([moderator_user_id]),
is_system_group: true,
direct_subgroup_ids: new Set([1]),
};
user_groups.initialize({realm_user_groups: [admins, moderators]});
assert.equal(settings_data.user_can_create_multiuse_invite(), false);
page_params.realm_create_multiuse_invite_group = 1;
page_params.user_id = admin_user_id;
assert.equal(settings_data.user_can_create_multiuse_invite(), true);
page_params.user_id = moderator_user_id;
assert.equal(settings_data.user_can_create_multiuse_invite(), false);
page_params.realm_create_multiuse_invite_group = 2;
page_params.user_id = moderator_user_id;
assert.equal(settings_data.user_can_create_multiuse_invite(), true);
page_params.user_id = member_user_id;
assert.equal(settings_data.user_can_create_multiuse_invite(), false);
});