mirror of https://github.com/zulip/zulip.git
org settings: Add setting to prevent users from adding bots.
Fixes: #7908.
This commit is contained in:
parent
7c830c5767
commit
777b6de689
|
@ -54,6 +54,10 @@ set_global('message_edit', {
|
|||
update_message_topic_editing_pencil: noop,
|
||||
});
|
||||
|
||||
set_global('settings_bots', {
|
||||
update_bot_permissions_ui: noop,
|
||||
});
|
||||
|
||||
// page_params is highly coupled to dispatching now
|
||||
set_global('page_params', {test_suite: false});
|
||||
var page_params = global.page_params;
|
||||
|
@ -195,11 +199,11 @@ var event_fixtures = {
|
|||
value: false,
|
||||
},
|
||||
|
||||
realm__update__create_generic_bot_by_admins_only: {
|
||||
realm__update__bot_creation_policy: {
|
||||
type: 'realm',
|
||||
op: 'update',
|
||||
property: 'create_generic_bot_by_admins_only',
|
||||
value: false,
|
||||
property: 'bot_creation_policy',
|
||||
value: 1,
|
||||
},
|
||||
|
||||
realm__update_dict__default: {
|
||||
|
|
|
@ -41,8 +41,6 @@ function _setup_page() {
|
|||
realm_email_changes_disabled: page_params.realm_email_changes_disabled,
|
||||
realm_add_emoji_by_admins_only: page_params.realm_add_emoji_by_admins_only,
|
||||
can_admin_emojis: page_params.is_admin || !page_params.realm_add_emoji_by_admins_only,
|
||||
realm_create_generic_bot_by_admins_only:
|
||||
page_params.realm_create_generic_bot_by_admins_only,
|
||||
realm_allow_message_deleting: page_params.realm_allow_message_deleting,
|
||||
realm_allow_message_editing: page_params.realm_allow_message_editing,
|
||||
realm_message_content_edit_limit_minutes:
|
||||
|
@ -62,10 +60,14 @@ function _setup_page() {
|
|||
realm_send_welcome_emails: page_params.realm_send_welcome_emails,
|
||||
};
|
||||
|
||||
options.bot_creation_policy_values = settings_bots.bot_creation_policy_values;
|
||||
var admin_tab = templates.render('admin_tab', options);
|
||||
$("#settings_content .organization-box").html(admin_tab);
|
||||
$("#settings_content .alert").removeClass("show");
|
||||
|
||||
settings_bots.update_bot_settings_tip();
|
||||
$("#id_realm_bot_creation_policy").val(page_params.realm_bot_creation_policy);
|
||||
|
||||
// Since we just swapped in a whole new page, we need to
|
||||
// tell admin_sections nothing is loaded.
|
||||
admin_sections.reset_sections();
|
||||
|
|
|
@ -56,7 +56,7 @@ exports.dispatch_normal_event = function dispatch_normal_event(event) {
|
|||
allow_edit_history: noop,
|
||||
allow_message_deleting: noop,
|
||||
allow_message_editing: noop,
|
||||
create_generic_bot_by_admins_only: noop,
|
||||
bot_creation_policy: settings_bots.update_bot_permissions_ui,
|
||||
create_stream_by_admins_only: noop,
|
||||
default_language: settings_org.reset_realm_default_language,
|
||||
description: settings_org.update_realm_description,
|
||||
|
|
|
@ -99,12 +99,17 @@ function _setup_page() {
|
|||
return tab;
|
||||
}());
|
||||
|
||||
settings_bots.setup_bot_creation_policy_values();
|
||||
|
||||
var settings_tab = templates.render('settings_tab', {
|
||||
full_name: people.my_full_name(),
|
||||
page_params: page_params,
|
||||
zuliprc: 'zuliprc',
|
||||
flaskbotrc: 'flaskbotrc',
|
||||
timezones: moment.tz.names(),
|
||||
admin_only_bot_creation: page_params.is_admin ||
|
||||
page_params.realm_bot_creation_policy !==
|
||||
settings_bots.bot_creation_policy_values.admins_only.code,
|
||||
});
|
||||
|
||||
$(".settings-box").html(settings_tab);
|
||||
|
|
|
@ -83,6 +83,57 @@ exports.generate_flaskbotrc_content = function (email, api_key) {
|
|||
"\n";
|
||||
};
|
||||
|
||||
exports.bot_creation_policy_values = {};
|
||||
|
||||
exports.setup_bot_creation_policy_values = function () {
|
||||
exports.bot_creation_policy_values = {
|
||||
everyone: {
|
||||
code: 1,
|
||||
description: i18n.t("Everyone"),
|
||||
},
|
||||
admins_only: {
|
||||
code: 3,
|
||||
description: i18n.t("Admins only"),
|
||||
},
|
||||
restricted: {
|
||||
code: 2,
|
||||
description: i18n.t("Everyone, but only admins can add generic bots"),
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
exports.update_bot_settings_tip = function () {
|
||||
var permission_type = exports.bot_creation_policy_values;
|
||||
var current_permission = page_params.realm_bot_creation_policy;
|
||||
var tip_text;
|
||||
if (current_permission === permission_type.admins_only.code) {
|
||||
tip_text = i18n.t("Only organization administrators can add bots to this organization");
|
||||
} else if (current_permission === permission_type.restricted.code) {
|
||||
tip_text = i18n.t("Only orgainzation administrators can add generic bots");
|
||||
} else {
|
||||
tip_text = i18n.t("Anyone in this organization can add bots");
|
||||
}
|
||||
$(".bot-settings-tip").text(tip_text);
|
||||
};
|
||||
|
||||
exports.update_bot_permissions_ui = function () {
|
||||
exports.update_bot_settings_tip();
|
||||
$('#bot_table_error').hide();
|
||||
$("#id_realm_bot_creation_policy").val(page_params.realm_bot_creation_policy);
|
||||
if (page_params.realm_bot_creation_policy ===
|
||||
exports.bot_creation_policy_values.admins_only.code &&
|
||||
!page_params.is_admin) {
|
||||
$('#create_bot_form').hide();
|
||||
$('.add-a-new-bot-tab').hide();
|
||||
$('.account-api-key-section').hide();
|
||||
$("#bots_lists_navbar .active-bots-tab").click();
|
||||
} else {
|
||||
$('#create_bot_form').show();
|
||||
$('.add-a-new-bot-tab').show();
|
||||
$('.account-api-key-section').show();
|
||||
}
|
||||
};
|
||||
|
||||
exports.set_up = function () {
|
||||
$('#payload_url_inputbox').hide();
|
||||
$('#create_payload_url').val('');
|
||||
|
@ -393,6 +444,7 @@ exports.set_up = function () {
|
|||
$("#add-a-new-bot-form").hide();
|
||||
$("#active_bots_list").show();
|
||||
$("#inactive_bots_list").hide();
|
||||
$('#bot_table_error').hide();
|
||||
});
|
||||
|
||||
$("#bots_lists_navbar .inactive-bots-tab").click(function (e) {
|
||||
|
|
|
@ -309,10 +309,9 @@ function _set_up() {
|
|||
checked_msg: i18n.t("Only administrators may now add new emoji!"),
|
||||
unchecked_msg: i18n.t("Any user may now add new emoji!"),
|
||||
},
|
||||
create_generic_bot_by_admins_only: {
|
||||
type: 'bool',
|
||||
checked_msg: i18n.t("Only administrators may now create new generic bots!"),
|
||||
unchecked_msg: i18n.t("Any user may now create new generic bots!"),
|
||||
bot_creation_policy: {
|
||||
type: 'integer',
|
||||
msg: i18n.t("Permissions changed"),
|
||||
},
|
||||
},
|
||||
};
|
||||
|
@ -361,7 +360,7 @@ function _set_up() {
|
|||
return;
|
||||
}
|
||||
|
||||
if (setting_type === 'text') {
|
||||
if (setting_type === 'text' || setting_type === 'integer') {
|
||||
ui_report.success(field_info.msg,
|
||||
property_type_status_element(key));
|
||||
return;
|
||||
|
|
|
@ -353,7 +353,7 @@ input[type=checkbox] + .inline-block {
|
|||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.organization-submission {
|
||||
.org-settings-form .organization-submission {
|
||||
margin-top: 0px;
|
||||
}
|
||||
|
||||
|
@ -1192,7 +1192,8 @@ input[type=checkbox].inline-block {
|
|||
transform: translateY(-50%);
|
||||
}
|
||||
|
||||
#id_realm_create_stream_permission {
|
||||
#id_realm_create_stream_permission,
|
||||
#id_realm_bot_creation_policy {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
<div id="admin-bot-list" class="settings-section" data-name="bot-list-admin">
|
||||
<div class="tip bot-settings-tip"></div>
|
||||
<input type="text" class="search" placeholder="{{t 'Filter bots' }}" aria-label="{{t 'Filter bots' }}"/>
|
||||
<div class="clear-float"></div>
|
||||
<table class="table table-condensed table-striped wrapped-table">
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
<div class="tip">
|
||||
{{#tr this}}Looking for our <a href="/integrations" target="_blank">Integrations</a> or <a href="/api" target="_blank">API</a> documentation?{{/tr}}
|
||||
</div>
|
||||
<div class="tip bot-settings-tip"></div>
|
||||
|
||||
<div>
|
||||
<span>{{t 'Download config of all active outgoing webhook bots in Zulip Botserver format.' }}</span>
|
||||
|
@ -14,7 +15,7 @@
|
|||
<ul class="nav nav-tabs nav-justified" id="bots_lists_navbar">
|
||||
<li class="active active-bots-tab"><a>{{t "Active bots" }}</a></li>
|
||||
<li class="inactive-bots-tab"><a>{{t "Inactive bots" }}</a></li>
|
||||
<li class="add-a-new-bot-tab"><a>{{t "Add a new bot" }}</a></li>
|
||||
<li class="add-a-new-bot-tab {{#unless admin_only_bot_creation}}hide{{/unless}}"><a>{{t "Add a new bot" }}</a></li>
|
||||
</ul>
|
||||
|
||||
<ol class="bots_list required-text" id="active_bots_list" data-empty="{{t 'You have no active bots.' }}">
|
||||
|
@ -26,7 +27,8 @@
|
|||
<div id="bot_table_error" class="alert alert-error hide"></div>
|
||||
|
||||
<div id="add-a-new-bot-form">
|
||||
<form id="create_bot_form" class="form-horizontal no-padding">
|
||||
<form id="create_bot_form"
|
||||
class="form-horizontal no-padding {{#unless admin_only_bot_creation}}hide{{/unless}}">
|
||||
<div class="new-bot-form">
|
||||
<div class="input-group">
|
||||
<label for="bot_type">
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
<div class="alert" id="admin-realm-name-changes-disabled-status"></div>
|
||||
<div class="alert" id="admin-realm-add-emoji-by-admins-only-status"></div>
|
||||
<div class="alert" id="admin-realm-create-stream-by-admins-only-status"></div>
|
||||
<div class="alert" id="admin-realm-create-generic-bot-by-admins-only-status"></div>
|
||||
<div class="alert" id="admin-realm-bot-creation-policy-status"></div>
|
||||
|
||||
<div class="inline-block organization-permissions-parent">
|
||||
<div class="input-group admin-restricted-to-domain">
|
||||
|
@ -74,8 +74,8 @@
|
|||
</div>
|
||||
|
||||
<h3>{{t "Other permissions" }}</h3>
|
||||
<div class="organization-permissions-parent">
|
||||
<div class="inline-block create-stream-dropdown">
|
||||
<div class="m-10 inline-block organization-permissions-parent">
|
||||
<div class="input-group create-stream-dropdown">
|
||||
<label for="realm_create_stream_permission" class="dropdown-title">{{t "Who can create streams" }}</label>
|
||||
<select name="realm_create_stream_permission" id="id_realm_create_stream_permission">
|
||||
<option value="by_anyone">{{t "Everyone" }}</option>
|
||||
|
@ -91,8 +91,16 @@
|
|||
class="admin-realm-message-content-edit-limit-minutes"
|
||||
value="{{ realm_waiting_period_threshold }}"/>
|
||||
</div>
|
||||
|
||||
<div class="input-group">
|
||||
<label for="realm_bot_creation_policy">{{t "Who can add bots" }}</label>
|
||||
<select name="realm_bot_creation_policy" id="id_realm_bot_creation_policy">
|
||||
{{#each bot_creation_policy_values}}
|
||||
<option value='{{this.code}}'>{{this.description}}</option>
|
||||
{{/each}}
|
||||
</select>
|
||||
</div>
|
||||
<div class="m-t-10 inline-block organization-permissions-parent">
|
||||
|
||||
<div class="inline-block">
|
||||
<label for="realm_add_emoji_by_admins_only" class="dropdown-title">{{t "Who can add emoji" }}</label>
|
||||
<select name="realm_add_emoji_by_admins_only" id="id_realm_add_emoji_by_admins_only">
|
||||
|
@ -102,21 +110,6 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<h3>{{t "Interactive bots" }}</h3>
|
||||
<div class="inline-block organization-permissions-parent">
|
||||
<div class="input-group">
|
||||
<label class="checkbox">
|
||||
<input type="checkbox" id="id_realm_create_generic_bot_by_admins_only" name="realm_create_generic_bot_by_admins_only"
|
||||
{{#if realm_create_generic_bot_by_admins_only}}checked="checked"{{/if}} />
|
||||
<span></span>
|
||||
</label>
|
||||
<label for="id_realm_create_generic_bot_by_admins_only" id="id_realm_create_generic_bot_by_admins_only_label" class="inline-block"
|
||||
title="{{t 'If checked, only administrators may create new generic bots.' }}">
|
||||
{{t "Prevent users from creating generic bots" }}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{#if is_admin }}
|
||||
<div class="input-group organization-submission">
|
||||
<button type="submit" class="button rounded sea-green">
|
||||
|
|
|
@ -40,6 +40,19 @@ def check_valid_bot_config(service_name: str, config_data: Dict[str, str]) -> No
|
|||
# error message.
|
||||
raise JsonableError(_("Invalid configuration data!"))
|
||||
|
||||
def check_bot_creation_policy(user_profile: UserProfile, bot_type: int) -> None:
|
||||
# Realm administrators can always add bot
|
||||
if user_profile.is_realm_admin:
|
||||
return
|
||||
|
||||
if user_profile.realm.bot_creation_policy == Realm.BOT_CREATION_EVERYONE:
|
||||
return
|
||||
if user_profile.realm.bot_creation_policy == Realm.BOT_CREATION_ADMINS_ONLY:
|
||||
raise JsonableError(_("Must be an organization administrator"))
|
||||
if user_profile.realm.bot_creation_policy == Realm.BOT_CREATION_LIMIT_GENERIC_BOTS and \
|
||||
bot_type == UserProfile.DEFAULT_BOT:
|
||||
raise JsonableError(_("Must be an organization administrator"))
|
||||
|
||||
def check_valid_bot_type(user_profile: UserProfile, bot_type: int) -> None:
|
||||
if bot_type not in user_profile.allowed_bot_types:
|
||||
raise JsonableError(_('Invalid bot type'))
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.6 on 2018-03-09 18:00
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
from django.db.backends.postgresql_psycopg2.schema import DatabaseSchemaEditor
|
||||
from django.db.migrations.state import StateApps
|
||||
|
||||
def set_initial_value_for_bot_creation_policy(apps: StateApps, schema_editor: DatabaseSchemaEditor) -> None:
|
||||
Realm = apps.get_model("zerver", "Realm")
|
||||
for realm in Realm.objects.all():
|
||||
if realm.create_generic_bot_by_admins_only:
|
||||
realm.bot_creation_policy = 2 # BOT_CREATION_LIMIT_GENERIC_BOTS
|
||||
else:
|
||||
realm.bot_creation_policy = 1 # BOT_CREATION_EVERYONE
|
||||
realm.save(update_fields=["bot_creation_policy"])
|
||||
|
||||
def reverse_code(apps: StateApps, schema_editor: DatabaseSchemaEditor) -> None:
|
||||
Realm = apps.get_model("zerver", "Realm")
|
||||
for realm in Realm.objects.all():
|
||||
if realm.bot_creation_policy == 1: # BOT_CREATION_EVERYONE
|
||||
realm.create_generic_bot_by_admins_only = False
|
||||
else:
|
||||
realm.create_generic_bot_by_admins_only = True
|
||||
realm.save(update_fields=["create_generic_bot_by_admins_only"])
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('zerver', '0142_userprofile_translate_emoticons'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='realm',
|
||||
name='bot_creation_policy',
|
||||
field=models.PositiveSmallIntegerField(default=1),
|
||||
),
|
||||
migrations.RunPython(set_initial_value_for_bot_creation_policy,
|
||||
reverse_code=reverse_code),
|
||||
]
|
|
@ -0,0 +1,19 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.6 on 2018-03-09 21:21
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('zerver', '0143_realm_bot_creation_policy'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='realm',
|
||||
name='create_generic_bot_by_admins_only',
|
||||
),
|
||||
]
|
|
@ -144,7 +144,6 @@ class Realm(models.Model):
|
|||
inline_url_embed_preview = models.BooleanField(default=True) # type: bool
|
||||
create_stream_by_admins_only = models.BooleanField(default=False) # type: bool
|
||||
add_emoji_by_admins_only = models.BooleanField(default=False) # type: bool
|
||||
create_generic_bot_by_admins_only = models.BooleanField(default=False) # type: bool
|
||||
mandatory_topics = models.BooleanField(default=False) # type: bool
|
||||
show_digest_email = models.BooleanField(default=True) # type: bool
|
||||
name_changes_disabled = models.BooleanField(default=False) # type: bool
|
||||
|
@ -164,6 +163,13 @@ class Realm(models.Model):
|
|||
COMMUNITY = 2
|
||||
org_type = models.PositiveSmallIntegerField(default=CORPORATE) # type: int
|
||||
|
||||
# This value is also being used in static/js/settings_bots.bot_creation_policy_values.
|
||||
# On updating it here, update it there as well.
|
||||
BOT_CREATION_EVERYONE = 1
|
||||
BOT_CREATION_LIMIT_GENERIC_BOTS = 2
|
||||
BOT_CREATION_ADMINS_ONLY = 3
|
||||
bot_creation_policy = models.PositiveSmallIntegerField(default=BOT_CREATION_EVERYONE) # type: int
|
||||
|
||||
date_created = models.DateTimeField(default=timezone_now) # type: datetime.datetime
|
||||
notifications_stream = models.ForeignKey('Stream', related_name='+', null=True, blank=True, on_delete=CASCADE) # type: Optional[Stream]
|
||||
signup_notifications_stream = models.ForeignKey('Stream', related_name='+', null=True, blank=True, on_delete=CASCADE) # type: Optional[Stream]
|
||||
|
@ -183,7 +189,7 @@ class Realm(models.Model):
|
|||
add_emoji_by_admins_only=bool,
|
||||
allow_edit_history=bool,
|
||||
allow_message_deleting=bool,
|
||||
create_generic_bot_by_admins_only=bool,
|
||||
bot_creation_policy=int,
|
||||
create_stream_by_admins_only=bool,
|
||||
default_language=Text,
|
||||
description=Text,
|
||||
|
@ -214,6 +220,12 @@ class Realm(models.Model):
|
|||
DEFAULT_NOTIFICATION_STREAM_NAME = u'announce'
|
||||
INITIAL_PRIVATE_STREAM_NAME = u'core team'
|
||||
|
||||
BOT_CREATION_POLICY_TYPES = [
|
||||
BOT_CREATION_EVERYONE,
|
||||
BOT_CREATION_LIMIT_GENERIC_BOTS,
|
||||
BOT_CREATION_ADMINS_ONLY,
|
||||
]
|
||||
|
||||
def authentication_methods_dict(self) -> Dict[Text, bool]:
|
||||
"""Returns the a mapping from authentication flags to their status,
|
||||
showing only those authentication flags that are supported on
|
||||
|
@ -724,7 +736,8 @@ class UserProfile(AbstractBaseUser, PermissionsMixin):
|
|||
def allowed_bot_types(self):
|
||||
# type: () -> List[int]
|
||||
allowed_bot_types = []
|
||||
if self.is_realm_admin or not self.realm.create_generic_bot_by_admins_only:
|
||||
if self.is_realm_admin or \
|
||||
not self.realm.bot_creation_policy == Realm.BOT_CREATION_LIMIT_GENERIC_BOTS:
|
||||
allowed_bot_types.append(UserProfile.DEFAULT_BOT)
|
||||
allowed_bot_types += [
|
||||
UserProfile.INCOMING_WEBHOOK_BOT,
|
||||
|
|
|
@ -570,7 +570,7 @@ class BotTest(ZulipTestCase, UploadSerializeMixin):
|
|||
self.assert_num_bots_equal(0)
|
||||
self.assert_json_error(result, 'Invalid bot type')
|
||||
|
||||
def test_add_bot_with_bot_type_not_allowed(self) -> None:
|
||||
def test_no_generic_bots_allowed_for_non_admins(self) -> None:
|
||||
bot_info = {
|
||||
'full_name': 'The Bot of Hamlet',
|
||||
'short_name': 'hambot',
|
||||
|
@ -578,15 +578,15 @@ class BotTest(ZulipTestCase, UploadSerializeMixin):
|
|||
}
|
||||
bot_email = 'hambot-bot@zulip.testserver'
|
||||
bot_realm = get_realm('zulip')
|
||||
bot_realm.create_generic_bot_by_admins_only = True
|
||||
bot_realm.save(update_fields=['create_generic_bot_by_admins_only'])
|
||||
bot_realm.bot_creation_policy = Realm.BOT_CREATION_LIMIT_GENERIC_BOTS
|
||||
bot_realm.save(update_fields=['bot_creation_policy'])
|
||||
|
||||
# A regular user cannot create a generic bot
|
||||
self.login(self.example_email('hamlet'))
|
||||
self.assert_num_bots_equal(0)
|
||||
result = self.client_post("/json/bots", bot_info)
|
||||
self.assert_num_bots_equal(0)
|
||||
self.assert_json_error(result, 'Invalid bot type')
|
||||
self.assert_json_error(result, 'Must be an organization administrator')
|
||||
|
||||
# But can create an incoming webhook
|
||||
self.assert_num_bots_equal(0)
|
||||
|
@ -595,11 +595,50 @@ class BotTest(ZulipTestCase, UploadSerializeMixin):
|
|||
profile = get_user(bot_email, bot_realm)
|
||||
self.assertEqual(profile.bot_type, UserProfile.INCOMING_WEBHOOK_BOT)
|
||||
|
||||
def test_add_bot_with_bot_type_not_allowed_admin(self) -> None:
|
||||
def test_no_generic_bots_allowed_for_admins(self) -> None:
|
||||
bot_email = 'hambot-bot@zulip.testserver'
|
||||
bot_realm = get_realm('zulip')
|
||||
bot_realm.create_generic_bot_by_admins_only = True
|
||||
bot_realm.save(update_fields=['create_generic_bot_by_admins_only'])
|
||||
bot_realm.bot_creation_policy = Realm.BOT_CREATION_LIMIT_GENERIC_BOTS
|
||||
bot_realm.save(update_fields=['bot_creation_policy'])
|
||||
|
||||
# An administrator can create any type of bot
|
||||
self.login(self.example_email('iago'))
|
||||
self.assert_num_bots_equal(0)
|
||||
self.create_bot(bot_type=UserProfile.DEFAULT_BOT)
|
||||
self.assert_num_bots_equal(1)
|
||||
profile = get_user(bot_email, bot_realm)
|
||||
self.assertEqual(profile.bot_type, UserProfile.DEFAULT_BOT)
|
||||
|
||||
def test_no_bots_allowed_for_non_admins(self) -> None:
|
||||
bot_info = {
|
||||
'full_name': 'The Bot of Hamlet',
|
||||
'short_name': 'hambot',
|
||||
'bot_type': 1,
|
||||
}
|
||||
bot_realm = get_realm('zulip')
|
||||
bot_realm.bot_creation_policy = Realm.BOT_CREATION_ADMINS_ONLY
|
||||
bot_realm.save(update_fields=['bot_creation_policy'])
|
||||
|
||||
# A regular user cannot create a generic bot
|
||||
self.login(self.example_email('hamlet'))
|
||||
self.assert_num_bots_equal(0)
|
||||
result = self.client_post("/json/bots", bot_info)
|
||||
self.assert_num_bots_equal(0)
|
||||
self.assert_json_error(result, 'Must be an organization administrator')
|
||||
|
||||
# Also, a regular user cannot create a incoming bot
|
||||
bot_info['bot_type'] = 2
|
||||
self.login(self.example_email('hamlet'))
|
||||
self.assert_num_bots_equal(0)
|
||||
result = self.client_post("/json/bots", bot_info)
|
||||
self.assert_num_bots_equal(0)
|
||||
self.assert_json_error(result, 'Must be an organization administrator')
|
||||
|
||||
def test_no_bots_allowed_for_admins(self) -> None:
|
||||
bot_email = 'hambot-bot@zulip.testserver'
|
||||
bot_realm = get_realm('zulip')
|
||||
bot_realm.bot_creation_policy = Realm.BOT_CREATION_ADMINS_ONLY
|
||||
bot_realm.save(update_fields=['bot_creation_policy'])
|
||||
|
||||
# An administrator can create any type of bot
|
||||
self.login(self.example_email('iago'))
|
||||
|
|
|
@ -1231,6 +1231,7 @@ class EventsRegisterTest(ZulipTestCase):
|
|||
message_retention_days=[10, 20],
|
||||
name=[u'Zulip', u'New Name'],
|
||||
waiting_period_threshold=[10, 20],
|
||||
bot_creation_policy=[Realm.BOT_CREATION_EVERYONE],
|
||||
) # type: Dict[str, Any]
|
||||
|
||||
vals = test_values.get(name)
|
||||
|
|
|
@ -109,9 +109,9 @@ class HomeTest(ZulipTestCase):
|
|||
"realm_allow_message_deleting",
|
||||
"realm_allow_message_editing",
|
||||
"realm_authentication_methods",
|
||||
"realm_bot_creation_policy",
|
||||
"realm_bot_domain",
|
||||
"realm_bots",
|
||||
"realm_create_generic_bot_by_admins_only",
|
||||
"realm_create_stream_by_admins_only",
|
||||
"realm_default_language",
|
||||
"realm_default_stream_groups",
|
||||
|
|
|
@ -295,6 +295,19 @@ class RealmTest(ZulipTestCase):
|
|||
realm = get_realm('zulip')
|
||||
self.assertFalse(realm.deactivated)
|
||||
|
||||
def test_change_bot_creation_policy(self) -> None:
|
||||
# We need an admin user.
|
||||
email = 'iago@zulip.com'
|
||||
self.login(email)
|
||||
req = dict(bot_creation_policy = ujson.dumps(Realm.BOT_CREATION_LIMIT_GENERIC_BOTS))
|
||||
result = self.client_patch('/json/realm', req)
|
||||
self.assert_json_success(result)
|
||||
|
||||
invalid_add_bot_permission = 4
|
||||
req = dict(bot_creation_policy = ujson.dumps(invalid_add_bot_permission))
|
||||
result = self.client_patch('/json/realm', req)
|
||||
self.assert_json_error(result, 'Invalid bot creation policy')
|
||||
|
||||
|
||||
class RealmAPITest(ZulipTestCase):
|
||||
|
||||
|
@ -329,6 +342,7 @@ class RealmAPITest(ZulipTestCase):
|
|||
message_retention_days=[10, 20],
|
||||
name=[u'Zulip', u'New Name'],
|
||||
waiting_period_threshold=[10, 20],
|
||||
bot_creation_policy=[1, 2],
|
||||
) # type: Dict[str, Any]
|
||||
vals = test_values.get(name)
|
||||
if Realm.property_types[name] is bool:
|
||||
|
|
|
@ -38,7 +38,6 @@ def update_realm(
|
|||
inline_url_embed_preview: Optional[bool]=REQ(validator=check_bool, default=None),
|
||||
create_stream_by_admins_only: Optional[bool]=REQ(validator=check_bool, default=None),
|
||||
add_emoji_by_admins_only: Optional[bool]=REQ(validator=check_bool, default=None),
|
||||
create_generic_bot_by_admins_only: Optional[bool]=REQ(validator=check_bool, default=None),
|
||||
allow_message_deleting: Optional[bool]=REQ(validator=check_bool, default=None),
|
||||
allow_message_editing: Optional[bool]=REQ(validator=check_bool, default=None),
|
||||
mandatory_topics: Optional[bool]=REQ(validator=check_bool, default=None),
|
||||
|
@ -50,7 +49,8 @@ def update_realm(
|
|||
notifications_stream_id: Optional[int]=REQ(validator=check_int, default=None),
|
||||
signup_notifications_stream_id: Optional[int]=REQ(validator=check_int, default=None),
|
||||
message_retention_days: Optional[int]=REQ(converter=to_not_negative_int_or_none, default=None),
|
||||
send_welcome_emails: Optional[bool]=REQ(validator=check_bool, default=None)
|
||||
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)
|
||||
) -> HttpResponse:
|
||||
realm = user_profile.realm
|
||||
|
||||
|
@ -67,6 +67,9 @@ def update_realm(
|
|||
if signup_notifications_stream_id is not None and settings.NEW_USER_BOT is None:
|
||||
return json_error(_("NEW_USER_BOT must configured first."))
|
||||
|
||||
# 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:
|
||||
return json_error(_("Invalid bot creation policy"))
|
||||
# The user of `locals()` here is a bit of a code smell, but it's
|
||||
# restricted to the elements present in realm.property_types.
|
||||
#
|
||||
|
|
|
@ -26,7 +26,7 @@ from zerver.lib.response import json_error, json_success
|
|||
from zerver.lib.streams import access_stream_by_name
|
||||
from zerver.lib.upload import upload_avatar_image
|
||||
from zerver.lib.validator import check_bool, check_string, check_int, check_url, check_dict
|
||||
from zerver.lib.users import check_valid_bot_type, \
|
||||
from zerver.lib.users import check_valid_bot_type, check_bot_creation_policy, \
|
||||
check_full_name, check_short_name, check_valid_interface_type, check_valid_bot_config
|
||||
from zerver.lib.utils import generate_random_token
|
||||
from zerver.models import UserProfile, Stream, Message, email_allowed_for_realm, \
|
||||
|
@ -299,6 +299,7 @@ def add_bot_backend(
|
|||
return json_error(_("Username already in use"))
|
||||
except UserProfile.DoesNotExist:
|
||||
pass
|
||||
check_bot_creation_policy(user_profile, bot_type)
|
||||
check_valid_bot_type(user_profile, bot_type)
|
||||
check_valid_interface_type(interface_type)
|
||||
|
||||
|
|
Loading…
Reference in New Issue