settings: Add support for Hangouts as the video chat provider.

The only thing that's annoying about this feature is that you need to
be a paying G Suite customer to use it.
This commit is contained in:
Vishnu Ks
2018-04-23 18:21:30 +05:30
committed by Tim Abbott
parent 01be6b01b1
commit c9e932a7ce
14 changed files with 133 additions and 2 deletions

View File

@@ -493,6 +493,7 @@ function test_sync_realm_settings() {
simulate_auth_methods();
$('#id_realm_create_stream_permission').change = set_callback('realm_create_stream_permission');
$('#id_realm_video_chat_provider').change = set_callback('realm_video_chat_provider');
$('#id_realm_invite_required').change = set_callback('change_invite_required');
$('#id_realm_restricted_to_domain').change = set_callback('id_realm_restricted_to_domain');
$('#id_realm_allow_message_editing').change = set_callback('change_message_editing');

View File

@@ -30,6 +30,7 @@ function _setup_page() {
var options = {
custom_profile_field_types: page_params.custom_profile_field_types,
realm_name: page_params.realm_name,
realm_available_video_chat_providers: page_params.realm_available_video_chat_providers,
realm_description: page_params.realm_description,
realm_restricted_to_domain: page_params.realm_restricted_to_domain,
realm_invite_required: page_params.realm_invite_required,

View File

@@ -924,8 +924,13 @@ exports.initialize = function () {
return;
}
var video_call_link;
var video_call_id = util.random_int(100000000000000, 999999999999999);
var video_call_link = page_params.jitsi_server_url + "/" + video_call_id;
if (page_params.realm_video_chat_provider === "Google Hangouts") {
video_call_link = "https://hangouts.google.com/hangouts/_/" + page_params.realm_google_hangouts_domain + "/" + video_call_id;
} else {
video_call_link = page_params.jitsi_server_url + "/" + video_call_id;
}
var video_call_link_text = '[' + _('Click to join video call') + '](' + video_call_link + ')';
compose_ui.insert_syntax_and_focus(video_call_link_text);
});

View File

@@ -63,6 +63,7 @@ exports.dispatch_normal_event = function dispatch_normal_event(event) {
description: noop,
email_changes_disabled: settings_account.update_email_change_display,
disallow_disposable_email_addresses: noop,
google_hangouts_domain: noop,
inline_image_preview: noop,
inline_url_embed_preview: noop,
invite_by_admins_only: noop,
@@ -76,6 +77,7 @@ exports.dispatch_normal_event = function dispatch_normal_event(event) {
send_welcome_emails: noop,
signup_notifications_stream_id: noop,
restricted_to_domain: noop,
video_chat_provider: noop,
waiting_period_threshold: noop,
};
if (event.op === 'update' && _.has(realm_settings, event.property)) {

View File

@@ -39,6 +39,14 @@ var org_settings = {
type: 'bool',
},
},
video_chat: {
video_chat_provider: {
type: 'text',
},
google_hangouts_domain: {
type: 'text',
},
},
user_defaults: {
default_language: {
type: 'text',
@@ -136,6 +144,17 @@ function set_add_emoji_permission_dropdown() {
$("#id_realm_add_emoji_by_admins_only").val(get_property_value("realm_add_emoji_by_admins_only"));
}
function set_video_chat_provider_dropdown() {
var chat_provider = page_params.realm_video_chat_provider;
$("#id_realm_video_chat_provider").val(chat_provider);
if (chat_provider === "Google Hangouts") {
$("#google_hangouts_domain").show();
$("#id_realm_google_hangouts_domain").val(page_params.realm_google_hangouts_domain);
} else {
$("#google_hangouts_domain").hide();
}
}
exports.populate_realm_domains = function (realm_domains) {
if (!meta.loaded) {
return;
@@ -280,6 +299,8 @@ function update_dependent_subsettings(property_name) {
} else if (property_name === 'realm_restricted_to_domain') {
settings_ui.disable_sub_setting_onchange(page_params.realm_restricted_to_domain,
"id_realm_disallow_disposable_email_addresses", false);
} else if (property_name === 'realm_video_chat_provider' || property_name === 'realm_google_hangouts_domain') {
set_video_chat_provider_dropdown();
}
}
@@ -397,6 +418,7 @@ function _set_up() {
set_create_stream_permission_dropdown();
set_add_emoji_permission_dropdown();
set_video_chat_provider_dropdown();
$("#id_realm_restricted_to_domain").change(function () {
settings_ui.disable_sub_setting_onchange(this.checked, "id_realm_disallow_disposable_email_addresses", false);
@@ -593,6 +615,16 @@ function _set_up() {
}
});
$("#id_realm_video_chat_provider").change(function (e) {
var video_chat_provider = e.target.value;
var node = $("#google_hangouts_domain");
if (video_chat_provider === "Google Hangouts") {
node.show();
} else {
node.hide();
}
});
$(".organization form.org-authentications-form").off('submit').on('submit', function (e) {
var authentication_methods_status = $("#admin-realm-authentication-methods-status").expectOne();

View File

@@ -91,6 +91,28 @@
</div>
</div>
<div id="org-video-chat" class="org-subsection-parent">
<div class="subsection-header">
<h3>{{t "Video chat provider" }}</h3>
{{ partial "settings-save-discard-widget" "section_name" "video-chat" }}
</div>
<div class="inline-block organization-settings-parent">
<div class="input-group">
<select name="realm_video_chat_provider" id="id_realm_video_chat_provider">
{{#each realm_available_video_chat_providers}}
<option value='{{this}}'>{{this}}</option>
{{/each}}
</select>
<div id="google_hangouts_domain">
<label>{{t 'Domain for your <a href="https://gsuite.google.com" target="_blank">G Suite team</a> (required)' }}:</label>
<input type="text" id="id_realm_google_hangouts_domain"
name="realm_google_hangouts_domain"
class="admin-realm-google-hangouts-domain"/>
</div>
</div>
</div>
</div>
<div id="org-user-defaults" class="org-subsection-parent">
<div class="subsection-header">
<h3>{{t "Default user settings" }}</h3>

View File

@@ -235,7 +235,7 @@
<h3>VIDEO CALLS</h3>
<p>
Create and join video calls with a single click. Powered
by Jitsi.
by your choice of Jitsi or Google Hangouts.
</p>
</div>
<div class="feature-block">

View File

@@ -168,6 +168,7 @@ def fetch_initial_state_data(user_profile: UserProfile,
state['max_icon_file_size'] = settings.MAX_ICON_FILE_SIZE
state['realm_bot_domain'] = realm.get_bot_domain()
state['realm_uri'] = realm.uri
state['realm_available_video_chat_providers'] = realm.VIDEO_CHAT_PROVIDERS
state['realm_presence_disabled'] = realm.presence_disabled
state['realm_show_digest_email'] = realm.show_digest_email and settings.SEND_DIGEST_EMAILS
state['realm_is_zephyr_mirror_realm'] = realm.is_zephyr_mirror_realm

View File

@@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.11 on 2018-04-23 16:37
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('zerver', '0158_realm_video_chat_provider'),
]
operations = [
migrations.AddField(
model_name='realm',
name='google_hangouts_domain',
field=models.TextField(default=''),
),
]

View File

@@ -139,6 +139,7 @@ class Realm(models.Model):
MAX_REALM_NAME_LENGTH = 40
MAX_REALM_SUBDOMAIN_LENGTH = 40
MAX_VIDEO_CHAT_PROVIDER_LENGTH = 40
MAX_GOOGLE_HANGOUTS_DOMAIN_LENGTH = 255 # This is just the maximum domain length by RFC
VIDEO_CHAT_PROVIDERS = [u"Jitsi", u"Google Hangouts"]
AUTHENTICATION_FLAGS = [u'Google', u'Email', u'GitHub', u'LDAP', u'Dev', u'RemoteUser']
SUBDOMAIN_FOR_ROOT_DOMAIN = ''
@@ -194,6 +195,7 @@ class Realm(models.Model):
# See upload_quota_bytes; don't interpret upload_quota_gb directly.
upload_quota_gb = models.IntegerField(null=True) # type: Optional[int]
video_chat_provider = models.CharField(default=u"Jitsi", max_length=MAX_VIDEO_CHAT_PROVIDER_LENGTH)
google_hangouts_domain = models.TextField(default="")
# Define the types of the various automatically managed properties
property_types = dict(
@@ -207,6 +209,7 @@ class Realm(models.Model):
description=Text,
disallow_disposable_email_addresses=bool,
email_changes_disabled=bool,
google_hangouts_domain=Text,
invite_required=bool,
invite_by_admins_only=bool,
inline_image_preview=bool,
@@ -217,6 +220,7 @@ class Realm(models.Model):
name_changes_disabled=bool,
restricted_to_domain=bool,
send_welcome_emails=bool,
video_chat_provider=Text,
waiting_period_threshold=int,
) # type: Dict[str, Union[type, Tuple[type, ...]]]

View File

@@ -1250,6 +1250,8 @@ class EventsRegisterTest(ZulipTestCase):
name=[u'Zulip', u'New Name'],
waiting_period_threshold=[10, 20],
bot_creation_policy=[Realm.BOT_CREATION_EVERYONE],
video_chat_provider=[u'Google Hangouts', u'Jitsi'],
google_hangouts_domain=[u"zulip.com", u"zulip.org"],
) # type: Dict[str, Any]
vals = test_values.get(name)

View File

@@ -112,6 +112,7 @@ class HomeTest(ZulipTestCase):
"realm_allow_message_deleting",
"realm_allow_message_editing",
"realm_authentication_methods",
"realm_available_video_chat_providers",
"realm_bot_creation_policy",
"realm_bot_domain",
"realm_bots",
@@ -128,6 +129,7 @@ class HomeTest(ZulipTestCase):
"realm_embedded_bots",
"realm_emoji",
"realm_filters",
"realm_google_hangouts_domain",
"realm_icon_source",
"realm_icon_url",
"realm_inline_image_preview",
@@ -152,6 +154,7 @@ class HomeTest(ZulipTestCase):
"realm_uri",
"realm_user_groups",
"realm_users",
"realm_video_chat_provider",
"realm_waiting_period_threshold",
"root_domain_uri",
"save_stacktraces",

View File

@@ -305,6 +305,34 @@ class RealmTest(ZulipTestCase):
result = self.client_patch('/json/realm', req)
self.assert_json_error(result, 'Invalid bot creation policy')
def test_change_video_chat_provider(self) -> None:
self.assertEqual(get_realm('zulip').video_chat_provider, "Jitsi")
email = self.example_email("iago")
self.login(email)
req = {"video_chat_provider": ujson.dumps("Google Hangouts")}
result = self.client_patch('/json/realm', req)
self.assert_json_error(result, "Invalid domain: Domain can't be empty.")
req = {
"video_chat_provider": ujson.dumps("Google Hangouts"),
"google_hangouts_domain": ujson.dumps("invaliddomain"),
}
result = self.client_patch('/json/realm', req)
self.assert_json_error(result, "Invalid domain: Domain must have at least one dot (.)")
req = {
"video_chat_provider": ujson.dumps("Google Hangouts"),
"google_hangouts_domain": ujson.dumps("zulip.com"),
}
result = self.client_patch('/json/realm', req)
self.assert_json_success(result)
self.assertEqual(get_realm('zulip').video_chat_provider, "Google Hangouts")
req = {"video_chat_provider": ujson.dumps("Jitsi")}
result = self.client_patch('/json/realm', req)
self.assert_json_success(result)
self.assertEqual(get_realm('zulip').video_chat_provider, "Jitsi")
class RealmAPITest(ZulipTestCase):
@@ -340,6 +368,8 @@ class RealmAPITest(ZulipTestCase):
name=[u'Zulip', u'New Name'],
waiting_period_threshold=[10, 20],
bot_creation_policy=[1, 2],
video_chat_provider=[u'Jitsi', u'Hangouts'],
google_hangouts_domain=[u'zulip.com', u'zulip.org'],
) # type: Dict[str, Any]
vals = test_values.get(name)
if Realm.property_types[name] is bool:

View File

@@ -20,6 +20,7 @@ from zerver.lib.request import has_request_variables, REQ, JsonableError
from zerver.lib.response import json_success, json_error
from zerver.lib.validator import check_string, check_dict, check_bool, check_int
from zerver.lib.streams import access_stream_by_id
from zerver.lib.domains import validate_domain
from zerver.models import Realm, UserProfile
from zerver.forms import check_subdomain_available as check_subdomain
@@ -54,6 +55,8 @@ def update_realm(
send_welcome_emails: Optional[bool]=REQ(validator=check_bool, default=None),
bot_creation_policy: Optional[int]=REQ(converter=to_not_negative_int_or_none, default=None),
default_twenty_four_hour_time: Optional[bool]=REQ(validator=check_bool, default=None),
video_chat_provider: Optional[Text]=REQ(validator=check_string, default=None),
google_hangouts_domain: Optional[Text]=REQ(validator=check_string, default=None)
) -> HttpResponse:
realm = user_profile.realm
@@ -67,6 +70,11 @@ def update_realm(
return json_error(_("Organization name is too long."))
if authentication_methods is not None and True not in list(authentication_methods.values()):
return json_error(_("At least one authentication method must be enabled."))
if video_chat_provider == "Google Hangouts":
try:
validate_domain(google_hangouts_domain)
except ValidationError as e:
return json_error(_('Invalid domain: {}').format(e.messages[0]))
# Additional validation of permissions values to add new bot
if bot_creation_policy is not None and bot_creation_policy not in Realm.BOT_CREATION_POLICY_TYPES: