diff --git a/frontend_tests/node_tests/dispatch.js b/frontend_tests/node_tests/dispatch.js index 89d754ade0b1f..b1912efcf1110 100644 --- a/frontend_tests/node_tests/dispatch.js +++ b/frontend_tests/node_tests/dispatch.js @@ -241,6 +241,13 @@ const event_fixtures = { value: 1, }, + realm__update__announcement_only_stream_post_policy: { + type: 'realm', + op: 'update', + property: 'announcement_only_stream_post_policy', + value: 2, + }, + realm__update__disallow_disposable_email_addresses: { type: 'realm', op: 'update', @@ -907,6 +914,10 @@ with_overrides(function (override) { event = event_fixtures.realm__update__invite_required; test_realm_boolean(event, 'realm_invite_required'); + event = event_fixtures.realm__update__announcement_only_stream_post_policy; + dispatch(event); + assert_same(page_params.realm_announcement_only_stream_post_policy, 2); + event = event_fixtures.realm__update__name; dispatch(event); assert_same(page_params.realm_name, 'new_realm_name'); diff --git a/frontend_tests/node_tests/settings_org.js b/frontend_tests/node_tests/settings_org.js index 0b916a73e0301..6916880a389ee 100644 --- a/frontend_tests/node_tests/settings_org.js +++ b/frontend_tests/node_tests/settings_org.js @@ -198,6 +198,7 @@ function test_submit_settings_form(submit_form) { realm_default_twenty_four_hour_time: 'false', realm_invite_to_stream_policy: 2, realm_create_stream_policy: 1, + realm_announcement_only_stream_post_policy: 1, }); global.patch_builtin('setTimeout', func => func()); @@ -257,6 +258,12 @@ function test_submit_settings_form(submit_form) { email_address_visibility_elem.data = () => { return "integer"; }; + const announcement_only_stream_post_policy_elem = $("#id_realm_announcement_only_stream_post_policy"); + announcement_only_stream_post_policy_elem.val('2'); + announcement_only_stream_post_policy_elem.attr("id", 'id_realm_announcement_only_stream_post_policy'); + announcement_only_stream_post_policy_elem.data = () => { + return "integer"; + }; let subsection_elem = $(`#org-${subsection}`); subsection_elem.closest = () => subsection_elem; @@ -266,6 +273,7 @@ function test_submit_settings_form(submit_form) { add_emoji_by_admins_only_elem, create_stream_policy_elem, invite_to_stream_policy_elem, + announcement_only_stream_post_policy_elem, ]); patched = false; @@ -279,6 +287,7 @@ function test_submit_settings_form(submit_form) { add_emoji_by_admins_only: false, create_stream_policy: '2', waiting_period_threshold: 10, + announcement_only_stream_post_policy: '2', }; assert.deepEqual(data, expected_value); @@ -647,6 +656,34 @@ function test_sync_realm_settings() { settings_org.sync_realm_settings('emails_restricted_to_domains'); assert.equal($("#id_realm_org_join_restrictions").val(), "no_restriction"); } + + { + /* Test that when announcement_only_stream_policy is set to "Anyone can react + and admin can post" that the dropdown is set to correct value */ + + const property_elem = $('#id_realm_announcement_only_stream_post_policy'); + property_elem.length = 1; + property_elem.attr('id', 'id_realm_announcement_only_stream_post_policy'); + + page_params.realm_announcement_only_stream_post_policy = 1; + + settings_org.sync_realm_settings('announcement_only_stream_post_policy'); + assert.equal($("#id_realm_announcement_only_stream_post_policy").val(), 1); + } + + { + /* Test that when announcement_only_stream_policy is set to "Only admin can + react and post" that the dropdown is set to correct value */ + + const property_elem = $('#id_realm_announcement_only_stream_post_policy'); + property_elem.length = 1; + property_elem.attr('id', 'id_realm_announcement_only_stream_post_policy'); + + page_params.realm_announcement_only_stream_post_policy = 2; + + settings_org.sync_realm_settings('announcement_only_stream_post_policy'); + assert.equal($("#id_realm_announcement_only_stream_post_policy").val(), 2); + } } function test_parse_time_limit() { diff --git a/static/js/admin.js b/static/js/admin.js index f99c15c78ddff..1ecfe2e363be5 100644 --- a/static/js/admin.js +++ b/static/js/admin.js @@ -76,6 +76,8 @@ exports.build_page = function () { upgrade_text_for_wide_organization_logo: page_params.upgrade_text_for_wide_organization_logo, realm_default_external_accounts: page_params.realm_default_external_accounts, + realm_announcement_only_stream_post_policy: + page_params.realm_announcement_only_stream_post_policy, }; options.admin_settings_label = admin_settings_label; diff --git a/static/js/click_handlers.js b/static/js/click_handlers.js index 3190e838b5945..47cff94a9183d 100644 --- a/static/js/click_handlers.js +++ b/static/js/click_handlers.js @@ -190,7 +190,10 @@ exports.initialize = function () { e.stopPropagation(); const local_id = $(this).attr('data-reaction-id'); const message_id = rows.get_message_id(this); - reactions.process_reaction_click(message_id, local_id); + const message = current_msg_list.get(message_id); + if (!message.is_stream || !reactions.set_restrict_emoji_reaction(message)) { + reactions.process_reaction_click(message_id, local_id); + } $(".tooltip").remove(); }); @@ -228,6 +231,12 @@ exports.initialize = function () { const elem = $(e.currentTarget); const local_id = elem.attr('data-reaction-id'); const message_id = rows.get_message_id(e.currentTarget); + const message = current_msg_list.get(message_id); + if (message.is_stream) { + if (reactions.set_restrict_emoji_reaction(message)) { + $(this).closest(".message_reaction").find(".disable-reaction-button").show(); + } + } const title = reactions.get_reaction_title_data(message_id, local_id); elem.tooltip({ @@ -245,6 +254,7 @@ exports.initialize = function () { $('#main_div').on('mouseleave', '.message_reaction', function (e) { e.stopPropagation(); $(e.currentTarget).tooltip('destroy'); + $(this).closest(".message_reaction").find(".disable-reaction-button").hide(); }); // DESTROY PERSISTING TOOLTIPS ON HOVER diff --git a/static/js/emoji_picker.js b/static/js/emoji_picker.js index 0a8899db8f474..9a9fdc634b635 100644 --- a/static/js/emoji_picker.js +++ b/static/js/emoji_picker.js @@ -689,12 +689,22 @@ exports.register_click_handlers = function () { e.stopPropagation(); const message_id = rows.get_message_id(this); - exports.toggle_emoji_popover(this, message_id); + const message = current_msg_list.get(message_id); + if (!message.is_stream || !reactions.set_restrict_emoji_reaction(message)) { + exports.toggle_emoji_popover(this, message_id); + } }); $("#main_div").on("mouseenter", ".reaction_button", function (e) { e.stopPropagation(); + const message_id = rows.get_message_id(this); + const message = current_msg_list.get(message_id); + if (message.is_stream) { + if (reactions.set_restrict_emoji_reaction(message)) { + $(this).find(".disable-emoji-icon").show(); + } + } const elem = $(e.currentTarget); const title = i18n.t("Add emoji reaction"); elem.tooltip({ @@ -708,6 +718,7 @@ exports.register_click_handlers = function () { }); $('#main_div').on('mouseleave', '.reaction_button', function (e) { + $(this).find(".disable-emoji-icon").hide(); e.stopPropagation(); $(e.currentTarget).tooltip('hide'); }); diff --git a/static/js/message_list_view.js b/static/js/message_list_view.js index bf4dba9ff06bf..01e5b338e577e 100644 --- a/static/js/message_list_view.js +++ b/static/js/message_list_view.js @@ -351,6 +351,8 @@ MessageListView.prototype = { if (message_container.msg.stream) { message_container.background_color = stream_data.get_color(message_container.msg.stream); + message_container.restrict_emoji_reaction = + reactions.set_restrict_emoji_reaction(message_container.msg); } message_container.contains_mention = message_container.msg.mentioned; diff --git a/static/js/reactions.js b/static/js/reactions.js index 0dbcfb061417b..31900c4f6f360 100644 --- a/static/js/reactions.js +++ b/static/js/reactions.js @@ -39,6 +39,13 @@ exports.current_user_has_reacted_to_emoji = function (message, emoji_code, type) }); }; +exports.set_restrict_emoji_reaction = function (message) { + if (page_params.realm_announcement_only_stream_post_policy === 1) { + return false; + } + return stream_data.get_announcement_only(message.stream) && !page_params.is_admin; +}; + function get_message(message_id) { const message = message_store.get(message_id); if (!message) { diff --git a/static/js/server_events_dispatch.js b/static/js/server_events_dispatch.js index 6b9d2182aa9ad..867a814726b64 100644 --- a/static/js/server_events_dispatch.js +++ b/static/js/server_events_dispatch.js @@ -88,6 +88,7 @@ exports.dispatch_normal_event = function dispatch_normal_event(event) { allow_message_deleting: noop, allow_message_editing: noop, allow_community_topic_editing: noop, + announcement_only_stream_post_policy: noop, user_group_edit_policy: noop, avatar_changes_disabled: settings_account.update_avatar_change_display, bot_creation_policy: settings_bots.update_bot_permissions_ui, @@ -146,6 +147,8 @@ exports.dispatch_normal_event = function dispatch_normal_event(event) { } else if (event.property === 'signup_notifications_stream_id') { settings_org.render_notifications_stream_ui( page_params.realm_signup_notifications_stream_id, 'signup_notifications'); + } else if (event.property === 'announcement_only_stream_post_policy') { + current_msg_list.rerender(); } if (event.property === 'name' && window.electron_bridge !== undefined) { diff --git a/static/js/settings_org.js b/static/js/settings_org.js index 22083caf769aa..b6ed14e19cea2 100644 --- a/static/js/settings_org.js +++ b/static/js/settings_org.js @@ -98,6 +98,17 @@ exports.private_message_policy_values = { }, }; +exports.announcement_only_stream_post_policy_values = { + anyone_can_react: { + code: 1, + description: i18n.t("Anyone can react and only admins can post"), + }, + admins_only: { + code: 2, + description: i18n.t("Only admins can react and post"), + }, +}; + exports.get_sorted_options_list = function (option_values_object) { const options_list = Object.keys(option_values_object).map((key) => { return _.extend(option_values_object[key], {key: key}); @@ -130,6 +141,8 @@ exports.get_organization_settings_options = () => { exports.user_group_edit_policy_values); options.private_message_policy_values = exports.get_sorted_options_list( exports.private_message_policy_values); + options.announcement_only_stream_post_policy_values = + exports.get_sorted_options_list(exports.announcement_only_stream_post_policy_values); return options; }; @@ -306,6 +319,11 @@ function set_video_chat_provider_dropdown() { } } +function set_announcement_only_stream_post_policy_dropdown() { + const value = get_property_value("realm_announcement_only_stream_post_policy"); + $("#id_realm_announcement_only_stream_post_policy").val(value); +} + const time_limit_dropdown_values = { any_time: { text: i18n.t("Any time"), @@ -557,6 +575,8 @@ function update_dependent_subsettings(property_name) { } else if (property_name === 'realm_digest_emails_enabled') { settings_notifications.set_enable_digest_emails_visibility(); set_digest_emails_weekday_visibility(); + } else if (property_name === 'realm_announcement_only_stream_post_policy') { + set_announcement_only_stream_post_policy_dropdown(); } } @@ -705,6 +725,7 @@ exports.build_page = function () { set_digest_emails_weekday_visibility(); set_user_group_edit_policy_dropdown(); set_private_message_policy_dropdown(); + set_announcement_only_stream_post_policy_dropdown(); function get_auth_method_table_data() { const new_auth_methods = {}; diff --git a/static/styles/reactions.scss b/static/styles/reactions.scss index 9755f6dbfe7f2..9f43472a48e31 100644 --- a/static/styles/reactions.scss +++ b/static/styles/reactions.scss @@ -13,12 +13,13 @@ background-color: hsl(0, 0%, 100%); border: 1px solid hsl(194, 37%, 84%); border-radius: 4px; + position: relative; &.reacted { background-color: hsl(195, 50%, 95%); } - &:hover { + &:not(.disabled):hover { border: 1px solid hsl(200, 100%, 40%); } @@ -64,7 +65,7 @@ color: hsl(0, 0%, 33%); } - &:hover .message_reaction + .reaction_button { + &:not(.disabled):hover .message_reaction + .reaction_button { visibility: visible; pointer-events: all; background-color: hsl(0, 0%, 98%); @@ -76,7 +77,7 @@ margin-right: 3px; } - &:hover i { + &:not(.disabled):hover i { color: hsl(200, 100%, 40%); } @@ -84,7 +85,7 @@ display: none; } - &:hover { + &:not(.disabled):hover { border: 1px solid hsl(200, 100%, 40%); background-color: hsl(195, 50%, 95%); cursor: pointer; @@ -296,3 +297,14 @@ .typeahead .emoji { top: 2px; } + +.disable-emoji-icon, +.disable-reaction-button { + display: none; + position: absolute; + width: 100%; + height: 2px; + background-color: hsl(0, 100%, 0%); + top: 8px; + left: 0px; +} diff --git a/static/styles/zulip.scss b/static/styles/zulip.scss index 04ed4c44de482..d382ec2d85cb8 100644 --- a/static/styles/zulip.scss +++ b/static/styles/zulip.scss @@ -647,7 +647,8 @@ td.pointer { display: inline-block; position: relative; color: hsl(0, 0%, 73%); - &:hover { + + &:not(.disabled):hover { color: hsl(200, 100%, 40%); } } diff --git a/static/templates/message_body.hbs b/static/templates/message_body.hbs index c79f2a746ac2d..27d5c50eeff2d 100644 --- a/static/templates/message_body.hbs +++ b/static/templates/message_body.hbs @@ -48,4 +48,4 @@
{{t "[More...]" }}
{{t "[Condense message]" }}
-
{{> message_reactions }}
+
{{> message_reactions}}
diff --git a/static/templates/message_controls.hbs b/static/templates/message_controls.hbs index d52e502b8fae2..cb49b51ba5883 100644 --- a/static/templates/message_controls.hbs +++ b/static/templates/message_controls.hbs @@ -4,8 +4,9 @@ {{/if}} {{#unless msg/sent_by_me}} -
- +
+ +
{{/unless}} diff --git a/static/templates/message_reaction.hbs b/static/templates/message_reaction.hbs index 2e0c5c8dbc4a2..cb5b75e1b4dd7 100644 --- a/static/templates/message_reaction.hbs +++ b/static/templates/message_reaction.hbs @@ -1,4 +1,4 @@ -
+
{{#if this.emoji_alt_code}}
 :{{this.emoji_name}}:
{{else}} @@ -8,5 +8,6 @@
{{/if}} {{/if}} +
{{this.count}}
diff --git a/static/templates/message_reactions.hbs b/static/templates/message_reactions.hbs index 995516fd80057..d31d63666249c 100644 --- a/static/templates/message_reactions.hbs +++ b/static/templates/message_reactions.hbs @@ -1,5 +1,5 @@ {{#each this/msg/message_reactions}} -{{> message_reaction}} +{{> message_reaction restrict_emoji_reaction = ../restrict_emoji_reaction}} {{/each}}
diff --git a/static/templates/settings/organization_permissions_admin.hbs b/static/templates/settings/organization_permissions_admin.hbs index 4cb5fb7997a18..e3dc9e3eeee83 100644 --- a/static/templates/settings/organization_permissions_admin.hbs +++ b/static/templates/settings/organization_permissions_admin.hbs @@ -134,6 +134,13 @@
+
+ + +
+