Embedded bots: Add support for creating embedded bots via the API.

Adds support to add "Embedded bot" Service objects. This service
handles every embedded bot.

Extracted from "Embedded bots: Add support to add embedded bots from
UI" by Robert Honig.

Tweaked by tabbott to be disabled by default.
This commit is contained in:
Abhijeet Kaur 2017-07-14 20:14:07 +05:30 committed by Tim Abbott
parent ce4ba9c178
commit a88178afaf
5 changed files with 58 additions and 4 deletions

View File

@ -515,6 +515,7 @@ class UserProfile(ModelReprMixin, AbstractBaseUser, PermissionsMixin):
DEFAULT_BOT,
INCOMING_WEBHOOK_BOT,
OUTGOING_WEBHOOK_BOT,
EMBEDDED_BOT,
]
SERVICE_BOT_TYPES = [

View File

@ -1001,3 +1001,43 @@ class BotTest(ZulipTestCase, UploadSerializeMixin):
bot_info['interface_type'] = Service.GENERIC
result = self.client_post("/json/bots", bot_info)
self.assert_json_success(result)
def test_create_embedded_bot(self, **extras):
# type: (**Any) -> None
self.login(self.example_email('hamlet'))
# Test to create embedded bot with correct service_name
bot_info = {
'full_name': 'Embedded test bot',
'short_name': 'embeddedservicebot',
'bot_type': UserProfile.EMBEDDED_BOT,
'service_name': 'converter',
}
bot_info.update(extras)
with self.settings(EMBEDDED_BOTS_ENABLED=False):
result = self.client_post("/json/bots", bot_info)
self.assert_json_error(result, 'Embedded bots are not enabled.')
result = self.client_post("/json/bots", bot_info)
self.assert_json_success(result)
bot_email = "embeddedservicebot-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, "converter")
self.assertEqual(service.user_profile, bot)
# Test to create embedded bot with incorrect service_name
bot_info = {
'full_name': 'Embedded test bot',
'short_name': 'embeddedservicebot',
'bot_type': UserProfile.EMBEDDED_BOT,
'service_name': 'not_existing_service',
}
bot_info.update(extras)
result = self.client_post("/json/bots", bot_info)
self.assert_json_error(result, 'Invalid embedded bot name.')

View File

@ -18,6 +18,7 @@ from zerver.lib.actions import do_change_avatar_fields, do_change_bot_owner, \
do_change_default_events_register_stream, do_change_default_sending_stream, \
do_create_user, do_deactivate_user, do_reactivate_user, do_regenerate_api_key
from zerver.lib.avatar import avatar_url, get_gravatar_url, get_avatar_field
from zerver.lib.integrations import EMBEDDED_BOTS
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
@ -233,6 +234,7 @@ def regenerate_bot_api_key(request, user_profile, email):
)
return json_success(json_result)
# Adds an outgoing webhook or embedded bot service.
def add_service(name, user_profile, base_url=None, interface=None, token=None):
# type: (Text, UserProfile, Text, int, Text) -> None
Service.objects.create(name=name,
@ -244,18 +246,26 @@ def add_service(name, user_profile, base_url=None, interface=None, token=None):
@has_request_variables
def add_bot_backend(request, user_profile, full_name_raw=REQ("full_name"), short_name_raw=REQ("short_name"),
bot_type=REQ(validator=check_int, default=UserProfile.DEFAULT_BOT),
payload_url=REQ(validator=check_url, default=None),
payload_url=REQ(validator=check_url, default=""),
service_name=REQ(default=None),
interface_type=REQ(validator=check_int, default=Service.GENERIC),
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], int, Optional[Text], Optional[Text], Optional[bool]) -> HttpResponse
# type: (HttpRequest, UserProfile, Text, Text, int, Optional[Text], Optional[Text], int, Optional[Text], Optional[Text], Optional[bool]) -> HttpResponse
short_name = check_short_name(short_name_raw)
service_name = short_name
service_name = service_name or short_name
short_name += "-bot"
full_name = check_full_name(full_name_raw)
email = '%s@%s' % (short_name, user_profile.realm.get_bot_domain())
form = CreateUserForm({'full_name': full_name, 'email': email})
if bot_type == UserProfile.EMBEDDED_BOT:
if not settings.EMBEDDED_BOTS_ENABLED:
return json_error(_("Embedded bots are not enabled."))
if service_name not in [bot.name for bot in EMBEDDED_BOTS]:
return json_error(_("Invalid embedded bot name."))
if not form.is_valid():
# We validate client-side as well
return json_error(_('Bad name or username'))
@ -297,7 +307,7 @@ def add_bot_backend(request, user_profile, full_name_raw=REQ("full_name"), short
user_file = list(request.FILES.values())[0]
upload_avatar_image(user_file, user_profile, bot_profile)
if bot_type == UserProfile.OUTGOING_WEBHOOK_BOT:
if bot_type in (UserProfile.OUTGOING_WEBHOOK_BOT, UserProfile.EMBEDDED_BOT):
add_service(name=service_name,
user_profile=bot_profile,
base_url=payload_url,

View File

@ -34,6 +34,8 @@ EXTRA_INSTALLED_APPS = ["zilencer", "analytics"]
CAMO_URI = ''
OPEN_REALM_CREATION = True
EMBEDDED_BOTS_ENABLED = True
SAVE_FRONTEND_STACKTRACES = True
EVENT_LOGS_ENABLED = True
SYSTEM_ONLY_REALMS = set() # type: Set[str]

View File

@ -183,6 +183,7 @@ DEFAULT_SETTINGS = {
'PUSH_NOTIFICATION_REDACT_CONTENT': False,
'RATE_LIMITING': True,
'SEND_LOGIN_EMAILS': True,
'EMBEDDED_BOTS_ENABLED': False,
}
# These settings are not documented in prod_settings_template.py.