Repository: zulip/zulip

Issue:
Add support for disabling the video call button
We got a request to disable Zulip's in-app video call button, which I think is pretty reasonable.

This can be implemented in the models.py layer by extending `VIDEO_CHAT_PROVIDERS` with an option for no button (value=0 makes sense for this to me).  And then that value should cause the video call button to be hidden in the frontend templates for both message editing and compose.

Tagging as a priority since it should be simple and valuable.

@sahil839 maybe this is a good issue for you?


Discussion:
Hello @zulip/server-compose members, this issue was labeled with the "area: compose" label, so you may want to check it out!

<!-- areaLabelAddition -->
@zulipbot claim

Resolving patch:
diff --git a/zerver/models.py b/zerver/models.py
--- a/zerver/models.py
+++ b/zerver/models.py
@@ -301,6 +301,10 @@ class Realm(models.Model):
     upload_quota_gb = models.IntegerField(null=True)  # type: Optional[int]
 
     VIDEO_CHAT_PROVIDERS = {
+        'disabled': {
+            'name': u"None",
+            'id': 0
+        },
         'jitsi_meet': {
             'name': u"Jitsi Meet",
             'id': 1


Test patch:
diff --git a/frontend_tests/node_tests/compose.js b/frontend_tests/node_tests/compose.js
--- a/frontend_tests/node_tests/compose.js
+++ b/frontend_tests/node_tests/compose.js
@@ -79,6 +79,22 @@ people.small_avatar_url_for_person = function () {
     return 'http://example.com/example.png';
 };
 
+function stub_out_video_calls() {
+    const elem = $("#below-compose-content .video_link");
+    elem.toggle = (show) => {
+        if (show) {
+            elem.show();
+        } else {
+            elem.hide();
+        }
+    };
+}
+
+function reset_jquery() {
+    // Avoid leaks.
+    set_global('$', global.make_zjquery());
+}
+
 const new_user = {
     email: 'new_user@example.com',
     user_id: 101,
@@ -912,6 +928,29 @@ run_test('initialize', () => {
         };
     };
 
+    page_params.realm_available_video_chat_providers = {
+        disabled: {
+            id: 0,
+            name: "disabled",
+        },
+        jitsi_meet: {
+            id: 1,
+            name: "Jitsi Meet",
+        },
+        google_hangouts: {
+            id: 2,
+            name: "Google Hangouts",
+        },
+        zoom: {
+            id: 3,
+            name: "Zoom",
+        },
+    };
+
+    page_params.realm_video_chat_provider =
+        page_params.realm_available_video_chat_providers.disabled.id;
+
+    stub_out_video_calls();
     compose.initialize();
 
     assert(resize_watch_manual_resize_checked);
@@ -919,11 +958,6 @@ run_test('initialize', () => {
     assert(!$("#compose #attach_files").hasClass("notdisplayed"));
     assert(setup_upload_called);
 
-    function reset_jquery() {
-        // Avoid leaks.
-        set_global('$', global.make_zjquery());
-    }
-
     let compose_actions_start_checked;
 
     function set_up_compose_start_mock(expected_opts) {
@@ -942,6 +976,7 @@ run_test('initialize', () => {
         page_params.narrow = true;
 
         reset_jquery();
+        stub_out_video_calls();
         set_up_compose_start_mock({});
 
         compose.initialize();
@@ -953,6 +988,7 @@ run_test('initialize', () => {
         page_params.narrow_topic = 'testing';
 
         reset_jquery();
+        stub_out_video_calls();
         set_up_compose_start_mock({topic: 'testing'});
 
         compose.initialize();
@@ -964,6 +1000,7 @@ run_test('initialize', () => {
         $("#compose-send-button").attr('disabled', 'disabled');
 
         reset_jquery();
+        stub_out_video_calls();
         compose.initialize();
 
         compose.abort_xhr();
@@ -1381,16 +1418,6 @@ run_test('on_events', () => {
                 to_$: () => textarea,
             },
         };
-        page_params.realm_available_video_chat_providers = {
-            google_hangouts: {
-                id: 2,
-                name: "Google Hangouts",
-            },
-            zoom: {
-                id: 3,
-                name: "Zoom",
-            },
-        };
 
         compose_ui.insert_syntax_and_focus = function (syntax) {
             syntax_to_insert = syntax;
@@ -1401,11 +1428,21 @@ run_test('on_events', () => {
         $('#compose-textarea').val('');
 
         handler(ev);
+        assert(!called);
+
+        page_params.realm_video_chat_provider =
+            page_params.realm_available_video_chat_providers.jitsi_meet.id;
+        handler(ev);
 
         // video link ids consist of 15 random digits
         let video_link_regex = /\[Click to join video call\]\(https:\/\/meet.jit.si\/\d{15}\)/;
         assert(video_link_regex.test(syntax_to_insert));
 
+        page_params.jitsi_server_url = null;
+        called = false;
+        handler(ev);
+        assert(!called);
+
         page_params.realm_video_chat_provider =
             page_params.realm_available_video_chat_providers.google_hangouts.id;
         page_params.realm_google_hangouts_domain = 'zulip';
@@ -1430,11 +1467,6 @@ run_test('on_events', () => {
         video_link_regex = /\[Click to join video call\]\(example\.zoom\.com\)/;
         assert(video_link_regex.test(syntax_to_insert));
 
-        page_params.jitsi_server_url = null;
-        called = false;
-
-        handler(ev);
-        assert(!called);
     }());
 
     (function test_markdown_preview_compose_clicked() {
@@ -1672,3 +1704,33 @@ run_test('narrow_button_titles', () => {
     assert.equal($("#left_bar_compose_stream_button_big").text(), i18n.t("New topic"));
     assert.equal($("#left_bar_compose_private_button_big").text(), i18n.t("New private message"));
 });
+
+run_test('test_video_chat_button_toggle', () => {
+    reset_jquery();
+    stub_out_video_calls();
+
+    page_params.realm_video_chat_provider =
+        page_params.realm_available_video_chat_providers.disabled.id;
+    compose.initialize();
+    assert.equal($("#below-compose-content .video_link").visible(), false);
+
+    reset_jquery();
+    stub_out_video_calls();
+    page_params.realm_video_chat_provider =
+        page_params.realm_available_video_chat_providers.jitsi_meet.id;
+    compose.initialize();
+    assert.equal($("#below-compose-content .video_link").visible(), false);
+
+    reset_jquery();
+    stub_out_video_calls();
+    page_params.jitsi_server_url = 'https://meet.jit.si';
+    compose.initialize();
+    assert.equal($("#below-compose-content .video_link").visible(), true);
+
+    reset_jquery();
+    stub_out_video_calls();
+    page_params.realm_video_chat_provider =
+        page_params.realm_available_video_chat_providers.google_hangouts.id;
+    compose.initialize();
+    assert.equal($("#below-compose-content .video_link").visible(), true);
+});
diff --git a/frontend_tests/node_tests/dispatch.js b/frontend_tests/node_tests/dispatch.js
--- a/frontend_tests/node_tests/dispatch.js
+++ b/frontend_tests/node_tests/dispatch.js
@@ -50,6 +50,10 @@ set_global('settings_bots', {
     update_bot_permissions_ui: noop,
 });
 
+set_global('compose', {
+    update_video_chat_button_display: noop,
+});
+
 set_global('settings_exports', {
     populate_exports_table: function (exports) {
         return exports;
diff --git a/frontend_tests/node_tests/ui_init.js b/frontend_tests/node_tests/ui_init.js
--- a/frontend_tests/node_tests/ui_init.js
+++ b/frontend_tests/node_tests/ui_init.js
@@ -187,6 +187,9 @@ $(".top_left_starred_messages").set_find_results('.count', count_stub);
 
 $("#tab_list .stream").length = 0;
 
+compose.compute_show_video_chat_button = () => {};
+$("#below-compose-content .video_link").toggle = () => {};
+
 run_test('initialize_everything', () => {
     ui_init.initialize_everything();
 });
diff --git a/zerver/tests/test_realm.py b/zerver/tests/test_realm.py
--- a/zerver/tests/test_realm.py
+++ b/zerver/tests/test_realm.py
@@ -498,7 +498,7 @@ def test_invalid_integer_attribute_values(self) -> None:
             invite_to_stream_policy=10,
             email_address_visibility=10,
             message_retention_days=10,
-            video_chat_provider=0,
+            video_chat_provider=4,
             waiting_period_threshold=-10,
             digest_weekday=10,
             user_group_edit_policy=10,
@@ -533,12 +533,18 @@ def test_change_video_chat_provider(self) -> None:
         self.assertEqual(get_realm('zulip').video_chat_provider, Realm.VIDEO_CHAT_PROVIDERS['jitsi_meet']['id'])
         self.login('iago')
 
-        invalid_video_chat_provider_value = 0
+        invalid_video_chat_provider_value = 4
         req = {"video_chat_provider": ujson.dumps(invalid_video_chat_provider_value)}
         result = self.client_patch('/json/realm', req)
         self.assert_json_error(result,
                                ("Invalid video_chat_provider {}").format(invalid_video_chat_provider_value))
 
+        req = {"video_chat_provider": ujson.dumps(Realm.VIDEO_CHAT_PROVIDERS['disabled']['id'])}
+        result = self.client_patch('/json/realm', req)
+        self.assert_json_success(result)
+        self.assertEqual(get_realm('zulip').video_chat_provider,
+                         Realm.VIDEO_CHAT_PROVIDERS['disabled']['id'])
+
         req = {"video_chat_provider": ujson.dumps(Realm.VIDEO_CHAT_PROVIDERS['google_hangouts']['id'])}
         result = self.client_patch('/json/realm', req)
         self.assert_json_error(result, "Invalid domain: Domain can't be empty.")