mirror of https://github.com/zulip/zulip.git
onboarding: Make Welcome Bot more interactive.
1. The initial welcome message now contains less detail. 2. The bot now responds to these commands: "apps", "edit profile", "dark mode", "light mode", "streams", "topics", "message formatting", "keyboard shortcuts" and "help" - the bot still responds if there are slight variations in these commands. 3. Tests have been made to check if bot responds to the advertised commands (with variations) and gives a negative message if it doesn't understand the message. With substantial tweaks by tabbott. Fixes #19900.
This commit is contained in:
parent
67f35d913a
commit
6404b7bf61
|
@ -68,38 +68,40 @@ def send_initial_pms(user: UserProfile) -> None:
|
||||||
" " + _("We also have a guide for [Setting up your organization]({help_url}).")
|
" " + _("We also have a guide for [Setting up your organization]({help_url}).")
|
||||||
).format(help_url=help_url)
|
).format(help_url=help_url)
|
||||||
|
|
||||||
welcome_msg = _("Hello, and welcome to Zulip!")
|
welcome_msg = _("Hello, and welcome to Zulip!") + "👋"
|
||||||
|
demo_org_warning = ""
|
||||||
if user.realm.demo_organization_scheduled_deletion_date is not None:
|
if user.realm.demo_organization_scheduled_deletion_date is not None:
|
||||||
welcome_msg += " " + _(
|
demo_org_warning = (
|
||||||
"Note that this is a [demo organization]({demo_org_help_url}) and will be automatically deleted in 30 days."
|
_(
|
||||||
|
"Note that this is a [demo organization]({demo_org_help_url}) and will be "
|
||||||
|
"**automatically deleted** in 30 days."
|
||||||
|
)
|
||||||
|
+ "\n\n"
|
||||||
)
|
)
|
||||||
|
|
||||||
content = "".join(
|
content = "".join(
|
||||||
[
|
[
|
||||||
welcome_msg + " ",
|
welcome_msg + " ",
|
||||||
_("This is a private message from me, Welcome Bot.") + "\n\n",
|
_("This is a private message from me, Welcome Bot.") + "\n\n",
|
||||||
"* "
|
_(
|
||||||
+ _(
|
|
||||||
"If you are new to Zulip, check out our [Getting started guide]({getting_started_url})!"
|
"If you are new to Zulip, check out our [Getting started guide]({getting_started_url})!"
|
||||||
|
),
|
||||||
|
"{organization_setup_text}" + "\n\n",
|
||||||
|
"{demo_org_warning}",
|
||||||
|
_(
|
||||||
|
"I can also help you get set up! Just click anywhere on this message or press `r` to reply."
|
||||||
)
|
)
|
||||||
+ "{organization_setup_text}\n",
|
+ "\n\n",
|
||||||
"* " + _("[Add a profile picture]({profile_url}).") + "\n",
|
_("Here are a few messages I understand:") + " ",
|
||||||
"* " + _("[Browse and subscribe to streams]({streams_url}).") + "\n",
|
bot_commands(is_initial_pm=True),
|
||||||
"* " + _("Download our [mobile and desktop apps]({apps_url}).") + " ",
|
|
||||||
_("Zulip also works great in a browser.") + "\n",
|
|
||||||
"* " + _("You can type `?` to learn more about Zulip shortcuts.") + "\n\n",
|
|
||||||
_("Practice sending a few messages by replying to this conversation.") + " ",
|
|
||||||
_("Click anywhere on this message or press `r` to reply."),
|
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
content = content.format(
|
content = content.format(
|
||||||
getting_started_url="/help/getting-started-with-zulip",
|
|
||||||
apps_url="/apps",
|
|
||||||
profile_url="#settings/profile",
|
|
||||||
streams_url="#streams/all",
|
|
||||||
organization_setup_text=organization_setup_text,
|
organization_setup_text=organization_setup_text,
|
||||||
|
demo_org_warning=demo_org_warning,
|
||||||
demo_org_help_url="/help/demo-organizations",
|
demo_org_help_url="/help/demo-organizations",
|
||||||
|
getting_started_url="/help/getting-started-with-zulip",
|
||||||
)
|
)
|
||||||
|
|
||||||
internal_send_private_message(
|
internal_send_private_message(
|
||||||
|
@ -107,21 +109,123 @@ def send_initial_pms(user: UserProfile) -> None:
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def bot_commands(is_initial_pm: bool = False) -> str:
|
||||||
|
commands = [
|
||||||
|
"apps",
|
||||||
|
"edit profile",
|
||||||
|
"theme",
|
||||||
|
"streams",
|
||||||
|
"topics",
|
||||||
|
"message formatting",
|
||||||
|
"keyboard shortcuts",
|
||||||
|
]
|
||||||
|
if is_initial_pm:
|
||||||
|
commands.append("help")
|
||||||
|
return ", ".join(["`" + command + "`" for command in commands]) + "."
|
||||||
|
|
||||||
|
|
||||||
|
def select_welcome_bot_response(human_response_lower: str) -> str:
|
||||||
|
# Given the raw (pre-markdown-rendering) content for a private
|
||||||
|
# message from the user to Welcome Bot, select the appropriate reply.
|
||||||
|
if human_response_lower in ["app", "apps"]:
|
||||||
|
return _(
|
||||||
|
"You can [download](/apps) the [mobile and desktop apps](/apps). "
|
||||||
|
"Zulip also works great in a browser."
|
||||||
|
)
|
||||||
|
elif human_response_lower == "profile":
|
||||||
|
return _(
|
||||||
|
"Go to [Profile settings](#settings/profile) "
|
||||||
|
"to add a [profile picture](/help/change-your-profile-picture) "
|
||||||
|
"and edit your [profile information](/help/edit-your-profile)."
|
||||||
|
)
|
||||||
|
elif human_response_lower == "theme":
|
||||||
|
return _(
|
||||||
|
"Go to [Display settings](#settings/display-settings) "
|
||||||
|
"to [switch between the light and dark themes](/help/dark-theme), "
|
||||||
|
"[pick your favorite emoji theme](/help/emoji-and-emoticons#change-your-emoji-set), "
|
||||||
|
"[change your language](/help/change-your-language), "
|
||||||
|
"and make other tweaks to your Zulip experience."
|
||||||
|
)
|
||||||
|
elif human_response_lower in ["stream", "streams", "channel", "channels"]:
|
||||||
|
return "".join(
|
||||||
|
[
|
||||||
|
_(
|
||||||
|
"In Zulip, streams [determine who gets a message](/help/streams-and-topics). "
|
||||||
|
"They are similar to channels in other chat apps."
|
||||||
|
)
|
||||||
|
+ "\n\n",
|
||||||
|
_("[Browse and subscribe to streams](#streams/all)."),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
elif human_response_lower in ["topic", "topics"]:
|
||||||
|
return "".join(
|
||||||
|
[
|
||||||
|
_(
|
||||||
|
"In Zulip, topics [tell you what a message is about](/help/streams-and-topics). "
|
||||||
|
"They are light-weight subjects, very similar to the subject line of an email."
|
||||||
|
)
|
||||||
|
+ "\n\n",
|
||||||
|
_(
|
||||||
|
"Check out [Recent topics](#recent_topics) to see what's happening! "
|
||||||
|
'You can return to this conversation by clicking "Private messages" in the upper left.'
|
||||||
|
),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
elif human_response_lower in ["keyboard", "shortcuts", "keyboard shortcuts"]:
|
||||||
|
return "".join(
|
||||||
|
[
|
||||||
|
_(
|
||||||
|
"Zulip's [keyboard shortcuts](#keyboard-shortcuts) "
|
||||||
|
"let you navigate the app quickly and efficiently."
|
||||||
|
)
|
||||||
|
+ "\n\n",
|
||||||
|
_("Press `?` any time to see a [cheat sheet](#keyboard-shortcuts)."),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
elif human_response_lower in ["formatting", "message formatting"]:
|
||||||
|
return "".join(
|
||||||
|
[
|
||||||
|
_(
|
||||||
|
"Zulip uses [Markdown](/help/format-your-message-using-markdown), "
|
||||||
|
"an intuitive format for **bold**, *italics*, bulleted lists, and more. "
|
||||||
|
"Click [here](#message-formatting) for a cheat sheet."
|
||||||
|
)
|
||||||
|
+ "\n\n",
|
||||||
|
_(
|
||||||
|
"Check out our [messaging tips](/help/messaging-tips) "
|
||||||
|
"to learn about emoji reactions, code blocks and much more!"
|
||||||
|
),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
elif human_response_lower in ["help", "?"]:
|
||||||
|
return "".join(
|
||||||
|
[
|
||||||
|
_("Here are a few messages I understand:") + " ",
|
||||||
|
bot_commands() + "\n\n",
|
||||||
|
_(
|
||||||
|
"Check out our [Getting started guide](/help/getting-started-with-zulip), "
|
||||||
|
"or browse the [Help center](/help/) to learn more!"
|
||||||
|
),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
return "".join(
|
||||||
|
[
|
||||||
|
_(
|
||||||
|
"I’m sorry, I did not understand your message. Please try one of the following commands:"
|
||||||
|
)
|
||||||
|
+ " ",
|
||||||
|
bot_commands(),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def send_welcome_bot_response(send_request: SendMessageRequest) -> None:
|
def send_welcome_bot_response(send_request: SendMessageRequest) -> None:
|
||||||
|
"""Given the send_request object for a private message from the user
|
||||||
|
to welcome-bot, trigger the welcome-bot reply."""
|
||||||
welcome_bot = get_system_bot(settings.WELCOME_BOT, send_request.message.sender.realm_id)
|
welcome_bot = get_system_bot(settings.WELCOME_BOT, send_request.message.sender.realm_id)
|
||||||
human_recipient_id = send_request.message.sender.recipient_id
|
human_response_lower = send_request.message.content.lower()
|
||||||
assert human_recipient_id is not None
|
content = select_welcome_bot_response(human_response_lower)
|
||||||
if Message.objects.filter(sender=welcome_bot, recipient_id=human_recipient_id).count() < 2:
|
|
||||||
content = (
|
|
||||||
_("Congratulations on your first reply!") + " "
|
|
||||||
":tada:"
|
|
||||||
"\n"
|
|
||||||
"\n"
|
|
||||||
+ _(
|
|
||||||
"Feel free to continue using this space to practice your new messaging "
|
|
||||||
"skills. Or, try clicking on some of the stream names to your left!"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
internal_send_private_message(welcome_bot, send_request.message.sender, content)
|
internal_send_private_message(welcome_bot, send_request.message.sender, content)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -32,22 +32,136 @@ class TutorialTests(ZulipTestCase):
|
||||||
user = self.example_user("hamlet")
|
user = self.example_user("hamlet")
|
||||||
self.assertEqual(user.tutorial_status, expected_db_status)
|
self.assertEqual(user.tutorial_status, expected_db_status)
|
||||||
|
|
||||||
def test_single_response_to_pm(self) -> None:
|
def test_response_to_pm_for_app(self) -> None:
|
||||||
user = self.example_user("hamlet")
|
user = self.example_user("hamlet")
|
||||||
bot = get_system_bot(settings.WELCOME_BOT, user.realm_id)
|
bot = get_system_bot(settings.WELCOME_BOT, user.realm_id)
|
||||||
content = "whatever"
|
messages = ["app", "Apps"]
|
||||||
self.login_user(user)
|
self.login_user(user)
|
||||||
|
for content in messages:
|
||||||
self.send_personal_message(user, bot, content)
|
self.send_personal_message(user, bot, content)
|
||||||
user_messages = message_stream_count(user)
|
|
||||||
expected_response = (
|
expected_response = (
|
||||||
"Congratulations on your first reply! :tada:\n\n"
|
"You can [download](/apps) the [mobile and desktop apps](/apps). "
|
||||||
"Feel free to continue using this space to practice your new messaging "
|
"Zulip also works great in a browser."
|
||||||
"skills. Or, try clicking on some of the stream names to your left!"
|
|
||||||
)
|
)
|
||||||
self.assertEqual(most_recent_message(user).content, expected_response)
|
self.assertEqual(most_recent_message(user).content, expected_response)
|
||||||
# Welcome bot shouldn't respond to further PMs.
|
|
||||||
|
def test_response_to_pm_for_edit(self) -> None:
|
||||||
|
user = self.example_user("hamlet")
|
||||||
|
bot = get_system_bot(settings.WELCOME_BOT, user.realm_id)
|
||||||
|
messages = ["profile", "Profile"]
|
||||||
|
self.login_user(user)
|
||||||
|
for content in messages:
|
||||||
self.send_personal_message(user, bot, content)
|
self.send_personal_message(user, bot, content)
|
||||||
self.assertEqual(message_stream_count(user), user_messages + 1)
|
expected_response = (
|
||||||
|
"Go to [Profile settings](#settings/profile) "
|
||||||
|
"to add a [profile picture](/help/change-your-profile-picture) "
|
||||||
|
"and edit your [profile information](/help/edit-your-profile)."
|
||||||
|
)
|
||||||
|
self.assertEqual(most_recent_message(user).content, expected_response)
|
||||||
|
|
||||||
|
def test_response_to_pm_for_theme(self) -> None:
|
||||||
|
user = self.example_user("hamlet")
|
||||||
|
bot = get_system_bot(settings.WELCOME_BOT, user.realm_id)
|
||||||
|
messages = ["theme", "Theme"]
|
||||||
|
self.login_user(user)
|
||||||
|
for content in messages:
|
||||||
|
self.send_personal_message(user, bot, content)
|
||||||
|
expected_response = (
|
||||||
|
"Go to [Display settings](#settings/display-settings) "
|
||||||
|
"to [switch between the light and dark themes](/help/dark-theme), "
|
||||||
|
"[pick your favorite emoji theme](/help/emoji-and-emoticons#change-your-emoji-set), "
|
||||||
|
"[change your language](/help/change-your-language), and make other tweaks to your Zulip experience."
|
||||||
|
)
|
||||||
|
self.assertEqual(most_recent_message(user).content, expected_response)
|
||||||
|
|
||||||
|
def test_response_to_pm_for_stream(self) -> None:
|
||||||
|
user = self.example_user("hamlet")
|
||||||
|
bot = get_system_bot(settings.WELCOME_BOT, user.realm_id)
|
||||||
|
messages = ["Streams", "streams", "channels"]
|
||||||
|
self.login_user(user)
|
||||||
|
for content in messages:
|
||||||
|
self.send_personal_message(user, bot, content)
|
||||||
|
expected_response = (
|
||||||
|
"In Zulip, streams [determine who gets a message](/help/streams-and-topics). "
|
||||||
|
"They are similar to channels in other chat apps.\n\n"
|
||||||
|
"[Browse and subscribe to streams](#streams/all)."
|
||||||
|
)
|
||||||
|
self.assertEqual(most_recent_message(user).content, expected_response)
|
||||||
|
|
||||||
|
def test_response_to_pm_for_topic(self) -> None:
|
||||||
|
user = self.example_user("hamlet")
|
||||||
|
bot = get_system_bot(settings.WELCOME_BOT, user.realm_id)
|
||||||
|
messages = ["Topics", "topics"]
|
||||||
|
self.login_user(user)
|
||||||
|
for content in messages:
|
||||||
|
self.send_personal_message(user, bot, content)
|
||||||
|
expected_response = (
|
||||||
|
"In Zulip, topics [tell you what a message is about](/help/streams-and-topics). "
|
||||||
|
"They are light-weight subjects, very similar to the subject line of an email.\n\n"
|
||||||
|
"Check out [Recent topics](#recent_topics) to see what's happening! "
|
||||||
|
'You can return to this conversation by clicking "Private messages" in the upper left.'
|
||||||
|
)
|
||||||
|
self.assertEqual(most_recent_message(user).content, expected_response)
|
||||||
|
|
||||||
|
def test_response_to_pm_for_shortcuts(self) -> None:
|
||||||
|
user = self.example_user("hamlet")
|
||||||
|
bot = get_system_bot(settings.WELCOME_BOT, user.realm_id)
|
||||||
|
messages = ["Keyboard shortcuts", "shortcuts", "Shortcuts"]
|
||||||
|
self.login_user(user)
|
||||||
|
for content in messages:
|
||||||
|
self.send_personal_message(user, bot, content)
|
||||||
|
expected_response = (
|
||||||
|
"Zulip's [keyboard shortcuts](#keyboard-shortcuts) "
|
||||||
|
"let you navigate the app quickly and efficiently.\n\n"
|
||||||
|
"Press `?` any time to see a [cheat sheet](#keyboard-shortcuts)."
|
||||||
|
)
|
||||||
|
self.assertEqual(most_recent_message(user).content, expected_response)
|
||||||
|
|
||||||
|
def test_response_to_pm_for_formatting(self) -> None:
|
||||||
|
user = self.example_user("hamlet")
|
||||||
|
bot = get_system_bot(settings.WELCOME_BOT, user.realm_id)
|
||||||
|
messages = ["message formatting", "Formatting"]
|
||||||
|
self.login_user(user)
|
||||||
|
for content in messages:
|
||||||
|
self.send_personal_message(user, bot, content)
|
||||||
|
expected_response = (
|
||||||
|
"Zulip uses [Markdown](/help/format-your-message-using-markdown), "
|
||||||
|
"an intuitive format for **bold**, *italics*, bulleted lists, and more. "
|
||||||
|
"Click [here](#message-formatting) for a cheat sheet.\n\n"
|
||||||
|
"Check out our [messaging tips](/help/messaging-tips) to learn about emoji reactions, "
|
||||||
|
"code blocks and much more!"
|
||||||
|
)
|
||||||
|
self.assertEqual(most_recent_message(user).content, expected_response)
|
||||||
|
|
||||||
|
def test_response_to_pm_for_help(self) -> None:
|
||||||
|
user = self.example_user("hamlet")
|
||||||
|
bot = get_system_bot(settings.WELCOME_BOT, user.realm_id)
|
||||||
|
messages = ["help", "Help", "?"]
|
||||||
|
self.login_user(user)
|
||||||
|
for content in messages:
|
||||||
|
self.send_personal_message(user, bot, content)
|
||||||
|
expected_response = (
|
||||||
|
"Here are a few messages I understand: "
|
||||||
|
"`apps`, `edit profile`, `theme`, "
|
||||||
|
"`streams`, `topics`, `message formatting`, `keyboard shortcuts`.\n\n"
|
||||||
|
"Check out our [Getting started guide](/help/getting-started-with-zulip), "
|
||||||
|
"or browse the [Help center](/help/) to learn more!"
|
||||||
|
)
|
||||||
|
self.assertEqual(most_recent_message(user).content, expected_response)
|
||||||
|
|
||||||
|
def test_response_to_pm_for_undefined(self) -> None:
|
||||||
|
user = self.example_user("hamlet")
|
||||||
|
bot = get_system_bot(settings.WELCOME_BOT, user.realm_id)
|
||||||
|
messages = ["Hello", "HAHAHA", "OKOK", "LalulaLapas"]
|
||||||
|
self.login_user(user)
|
||||||
|
for content in messages:
|
||||||
|
self.send_personal_message(user, bot, content)
|
||||||
|
expected_response = (
|
||||||
|
"I’m sorry, I did not understand your message. Please try one of the following commands: "
|
||||||
|
"`apps`, `edit profile`, `theme`, `streams`, "
|
||||||
|
"`topics`, `message formatting`, `keyboard shortcuts`."
|
||||||
|
)
|
||||||
|
self.assertEqual(most_recent_message(user).content, expected_response)
|
||||||
|
|
||||||
def test_no_response_to_group_pm(self) -> None:
|
def test_no_response_to_group_pm(self) -> None:
|
||||||
user1 = self.example_user("hamlet")
|
user1 = self.example_user("hamlet")
|
||||||
|
|
Loading…
Reference in New Issue