mirror of https://github.com/zulip/zulip.git
Outgoing webhook System: first Iteration of outgoing webhook UI.
This commit is contained in:
parent
f32c1892ff
commit
33c0c00cd6
|
@ -75,6 +75,8 @@ exports.set_up = function () {
|
|||
$("#get_api_key_box").hide();
|
||||
$("#show_api_key_box").hide();
|
||||
$("#api_key_button_box").show();
|
||||
$('#payload_url_inputbox').hide();
|
||||
$('#create_payload_url').val('');
|
||||
|
||||
$('#api_key_button').click(function () {
|
||||
if (page_params.realm_password_auth_enabled !== false) {
|
||||
|
@ -119,6 +121,8 @@ exports.set_up = function () {
|
|||
|
||||
|
||||
var create_avatar_widget = avatar.build_bot_create_widget();
|
||||
var OUTGOING_WEBHOOK_BOT_TYPE = '3';
|
||||
var GENERIC_BOT_TYPE = '1';
|
||||
|
||||
$('#create_bot_form').validate({
|
||||
errorClass: 'text-error',
|
||||
|
@ -129,12 +133,18 @@ exports.set_up = function () {
|
|||
var bot_type = $('#create_bot_type :selected').val();
|
||||
var full_name = $('#create_bot_name').val();
|
||||
var short_name = $('#create_bot_short_name').val() || $('#create_bot_short_name').text();
|
||||
var payload_url = $('#create_payload_url').val();
|
||||
var formData = new FormData();
|
||||
|
||||
formData.append('csrfmiddlewaretoken', csrf_token);
|
||||
formData.append('bot_type', bot_type);
|
||||
formData.append('full_name', full_name);
|
||||
formData.append('short_name', short_name);
|
||||
|
||||
// If the selected bot_type is Outgoing webhook
|
||||
if (bot_type === OUTGOING_WEBHOOK_BOT_TYPE) {
|
||||
formData.append('payload_url', JSON.stringify(payload_url));
|
||||
}
|
||||
jQuery.each($('#bot_avatar_file_input')[0].files, function (i, file) {
|
||||
formData.append('file-'+i, file);
|
||||
});
|
||||
|
@ -149,6 +159,9 @@ exports.set_up = function () {
|
|||
$('#bot_table_error').hide();
|
||||
$('#create_bot_name').val('');
|
||||
$('#create_bot_short_name').val('');
|
||||
$('#create_payload_url').val('');
|
||||
$('#payload_url_inputbox').hide();
|
||||
$('#create_bot_type').val(GENERIC_BOT_TYPE);
|
||||
$('#create_bot_button').show();
|
||||
create_avatar_widget.clear();
|
||||
},
|
||||
|
@ -162,6 +175,18 @@ exports.set_up = function () {
|
|||
},
|
||||
});
|
||||
|
||||
$("#create_bot_type").on("change", function () {
|
||||
var bot_type = $('#create_bot_type :selected').val();
|
||||
// If the selected bot_type is Outgoing webhook
|
||||
if (bot_type === OUTGOING_WEBHOOK_BOT_TYPE) {
|
||||
$('#payload_url_inputbox').show();
|
||||
$('#create_payload_url').addClass('required');
|
||||
} else {
|
||||
$('#payload_url_inputbox').hide();
|
||||
$('#create_payload_url').removeClass('required');
|
||||
}
|
||||
});
|
||||
|
||||
$("#active_bots_list").on("click", "button.delete_bot", function (e) {
|
||||
var email = $(e.currentTarget).data('email');
|
||||
channel.del({
|
||||
|
|
|
@ -1212,3 +1212,7 @@ thead .actions {
|
|||
.required-text.thick:empty::after {
|
||||
width: 200%;
|
||||
}
|
||||
|
||||
#payload_url_inputbox input[type=text] {
|
||||
width: 340px;
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
<select name="bot_type" id="create_bot_type">
|
||||
<option value="1">{{t "Generic bot" }}</option>
|
||||
<option value="2">{{t "Incoming webhook" }}</option>
|
||||
<option value="3">{{t "Outgoing webhook" }}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
|
@ -50,6 +51,12 @@
|
|||
<label for="create_bot_short_name" generated="true" class="text-error"></label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="input-group" id="payload_url_inputbox">
|
||||
<label for="create_payload_url">{{t "Outgoing webhook service base URL" }}</label>
|
||||
<input type="text" name="payload_url" id="create_payload_url"
|
||||
maxlength=100 placeholder="https://hostname.example.com/bots/followup" value="" />
|
||||
<div><label for="create_payload_url" generated="true" class="text-error"></label></div>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<div id="bot_avatar_file"></div>
|
||||
<input type="file" name="bot_avatar_file_input" class="notvisible" id="bot_avatar_file_input" value="{{t 'Upload avatar' }}" />
|
||||
|
|
|
@ -157,6 +157,8 @@ def build_custom_checkers(by_lang):
|
|||
"return json_error(_(\"Email '%(email)s' not allowed for realm '%(realm)s'\") %"),
|
||||
('zproject/settings.py',
|
||||
"'format': '%(asctime)s %(levelname)-8s %(message)s'"),
|
||||
('static/templates/settings/bot-settings.handlebars',
|
||||
"'https://hostname.example.com/bots/followup'"),
|
||||
]),
|
||||
'description': 'Missing space around "%"'},
|
||||
# This rule is constructed with + to avoid triggering on itself
|
||||
|
|
|
@ -528,6 +528,7 @@ class UserProfile(ModelReprMixin, AbstractBaseUser, PermissionsMixin):
|
|||
since they can't be used to read messages.
|
||||
"""
|
||||
INCOMING_WEBHOOK_BOT = 2
|
||||
# This value is also being used in static/js/settings_bots.js. On updating it here, update it there as well.
|
||||
OUTGOING_WEBHOOK_BOT = 3
|
||||
"""
|
||||
Embedded bots run within the Zulip server itself; events are added to the
|
||||
|
@ -539,6 +540,7 @@ class UserProfile(ModelReprMixin, AbstractBaseUser, PermissionsMixin):
|
|||
ALLOWED_BOT_TYPES = [
|
||||
DEFAULT_BOT,
|
||||
INCOMING_WEBHOOK_BOT,
|
||||
OUTGOING_WEBHOOK_BOT,
|
||||
]
|
||||
|
||||
SERVICE_BOT_TYPES = [
|
||||
|
|
|
@ -13,7 +13,7 @@ from typing import Any, Dict, List
|
|||
|
||||
from zerver.lib.actions import do_change_stream_invite_only
|
||||
from zerver.models import get_realm, get_stream, \
|
||||
Realm, Stream, UserProfile, get_user
|
||||
Realm, Stream, UserProfile, get_user, get_bot_services
|
||||
from zerver.lib.test_classes import ZulipTestCase, UploadSerializeMixin
|
||||
from zerver.lib.test_helpers import (
|
||||
avatar_disk_path, get_test_image_file, tornado_redirected_to_list,
|
||||
|
@ -911,3 +911,32 @@ class BotTest(ZulipTestCase, UploadSerializeMixin):
|
|||
result = self.client_patch("/json/bots/nonexistent-bot@zulip.com", bot_info)
|
||||
self.assert_json_error(result, 'No such user')
|
||||
self.assert_num_bots_equal(1)
|
||||
|
||||
def test_create_outgoing_webhook_bot(self, **extras):
|
||||
# type: (**Any) -> None
|
||||
self.login(self.example_email('hamlet'))
|
||||
bot_info = {
|
||||
'full_name': 'Outgoing Webhook test bot',
|
||||
'short_name': 'outgoingservicebot',
|
||||
'bot_type': UserProfile.OUTGOING_WEBHOOK_BOT,
|
||||
'payload_url': ujson.dumps('http://127.0.0.1:5002/bots/followup'),
|
||||
}
|
||||
bot_info.update(extras)
|
||||
result = self.client_post("/json/bots", bot_info)
|
||||
self.assert_json_success(result)
|
||||
|
||||
bot_email = "outgoingservicebot-bot@zulip.testserver"
|
||||
bot_realm = get_realm('zulip')
|
||||
bot = get_user(bot_email, bot_realm)
|
||||
services = get_bot_services(bot.id)
|
||||
service = services[0]
|
||||
|
||||
self.assertEqual(len(services), 1)
|
||||
self.assertEqual(service.name, "outgoingservicebot")
|
||||
self.assertEqual(service.base_url, "http://127.0.0.1:5002/bots/followup")
|
||||
self.assertEqual(service.user_profile, bot)
|
||||
|
||||
# invalid URL test case.
|
||||
bot_info['payload_url'] = ujson.dumps('http://127.0.0.:5002/bots/followup')
|
||||
result = self.client_post("/json/bots", bot_info)
|
||||
self.assert_json_error(result, "Enter a valid URL.")
|
||||
|
|
|
@ -22,11 +22,12 @@ from zerver.lib.avatar import avatar_url, get_avatar_url
|
|||
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
|
||||
from zerver.lib.validator import check_bool, check_string, check_int, check_url
|
||||
from zerver.lib.users import check_valid_bot_type, check_change_full_name, check_full_name
|
||||
from zerver.lib.utils import generate_random_token
|
||||
from zerver.models import UserProfile, Stream, Realm, Message, get_user_profile_by_email, \
|
||||
email_allowed_for_realm, get_user_profile_by_id, get_user
|
||||
email_allowed_for_realm, get_user_profile_by_id, get_user, Service
|
||||
from zerver.lib.create_user import random_api_key
|
||||
|
||||
|
||||
def deactivate_user_backend(request, user_profile, email):
|
||||
|
@ -229,13 +230,23 @@ def regenerate_bot_api_key(request, user_profile, email):
|
|||
)
|
||||
return json_success(json_result)
|
||||
|
||||
def add_outgoing_webhook_service(name, user_profile, base_url, interface, token):
|
||||
# type: (Text, UserProfile, Text, int, Text) -> None
|
||||
Service.objects.create(name=name,
|
||||
user_profile=user_profile,
|
||||
base_url=base_url,
|
||||
interface=interface,
|
||||
token=token)
|
||||
|
||||
@has_request_variables
|
||||
def add_bot_backend(request, user_profile, full_name_raw=REQ("full_name"), short_name=REQ(),
|
||||
bot_type=REQ(validator=check_int, default=UserProfile.DEFAULT_BOT),
|
||||
payload_url=REQ(validator=check_url, default=None),
|
||||
default_sending_stream_name=REQ('default_sending_stream', default=None),
|
||||
default_events_register_stream_name=REQ('default_events_register_stream', default=None),
|
||||
default_all_public_streams=REQ(validator=check_bool, default=None)):
|
||||
# type: (HttpRequest, UserProfile, Text, Text, int, Optional[Text], Optional[Text], Optional[bool]) -> HttpResponse
|
||||
# type: (HttpRequest, UserProfile, Text, Text, int, Optional[Text], Optional[Text], Optional[Text], Optional[bool]) -> HttpResponse
|
||||
service_name = short_name
|
||||
short_name += "-bot"
|
||||
full_name = check_full_name(full_name_raw)
|
||||
email = '%s@%s' % (short_name, user_profile.realm.get_bot_domain())
|
||||
|
@ -279,6 +290,14 @@ def add_bot_backend(request, user_profile, full_name_raw=REQ("full_name"), short
|
|||
if len(request.FILES) == 1:
|
||||
user_file = list(request.FILES.values())[0]
|
||||
upload_avatar_image(user_file, user_profile, bot_profile)
|
||||
|
||||
if bot_type == UserProfile.OUTGOING_WEBHOOK_BOT:
|
||||
add_outgoing_webhook_service(name=service_name,
|
||||
user_profile=bot_profile,
|
||||
base_url=payload_url,
|
||||
interface=1,
|
||||
token=random_api_key())
|
||||
|
||||
json_result = dict(
|
||||
api_key=bot_profile.api_key,
|
||||
avatar_url=avatar_url(bot_profile),
|
||||
|
|
Loading…
Reference in New Issue