From 9ce4260662ffa23952801b6ee163244634f2c908 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9=20=D0=9C=D1=83?= =?UTF-8?q?=D1=80=D0=B0=D1=82=D0=BE=D0=B2?= Date: Mon, 12 Jun 2023 00:15:04 +0300 Subject: [PATCH 01/12] add menu buttons --- src/application.py | 6 ++-- src/bot/constants/info/menu.py | 14 +++++++-- src/bot/constants/key.py | 2 ++ src/bot/conversations/main_application.py | 11 ++++--- src/bot/conversations/menu_application.py | 37 +++++++++++++++++++++-- src/bot/core/logger.py | 2 +- src/bot/core/settings.py | 2 +- src/bot/handlers.py | 21 +++++++------ src/bot/utils.py | 2 +- 9 files changed, 73 insertions(+), 24 deletions(-) diff --git a/src/application.py b/src/application.py index 52457a7..56056a1 100644 --- a/src/application.py +++ b/src/application.py @@ -1,8 +1,8 @@ from telegram.ext import Application -from bot.core import logger # noqa -from bot.core.settings import settings -from bot.handlers import main_handler, greet_new_member_handler +from src.bot.core import logger # noqa +from src.bot.core.settings import settings +from src.bot.handlers import main_handler, greet_new_member_handler def main() -> None: diff --git a/src/bot/constants/info/menu.py b/src/bot/constants/info/menu.py index 1c312f0..7e3f904 100644 --- a/src/bot/constants/info/menu.py +++ b/src/bot/constants/info/menu.py @@ -1,4 +1,4 @@ -from bot.constants import key +from src.bot.constants import key MAIN_MENU = { @@ -7,6 +7,7 @@ key.DESCRIPTION: "Временное описание кнопки главного меню", key.MENU: [ f"{key.MENU}_SUB", + f"{key.MENU}_SUB2", ], } } @@ -23,10 +24,19 @@ f"{key.MENU}_SUB2": { key.NAME: "Кнопка 2", key.DESCRIPTION: "Описание 2", - key.PARENT: f"{key.MENU}_SUB", + key.PARENT: f"{key.MENU}_MAIN", + key.MENU: [ + f"{key.MENU}_SUB3", + ], }, + f"{key.MENU}_SUB3": { + key.NAME: "Назад", + key.DESCRIPTION: "Описание 3", + key.PARENT: f"{key.MENU}_MAIN", + } } + ALL_MENU = { **MAIN_MENU, **SUBMENU, diff --git a/src/bot/constants/key.py b/src/bot/constants/key.py index 5460b7a..d3f85b2 100644 --- a/src/bot/constants/key.py +++ b/src/bot/constants/key.py @@ -2,3 +2,5 @@ NAME = "NAME" DESCRIPTION = "DESCRIPTION" ASK = "ASK" +PARENT = "PARENT" + diff --git a/src/bot/conversations/main_application.py b/src/bot/conversations/main_application.py index 8207958..257fd94 100644 --- a/src/bot/conversations/main_application.py +++ b/src/bot/conversations/main_application.py @@ -2,11 +2,14 @@ from telegram.constants import ParseMode from telegram.ext import ContextTypes, ConversationHandler -from bot.constants import state +from src.bot.constants import state # from bot.constants.info.menu import ALL_MENU # uncomment after adding the menu manager -from bot.constants.info.text import START_MESSAGE, STOP_MESSAGE, WELCOME_MESSAGE -from bot.conversations.menu_application import menu +from src.bot.constants.info.text import START_MESSAGE, STOP_MESSAGE, WELCOME_MESSAGE +from src.bot.conversations.menu_application import menu + +from src.bot.constants import key +from src.bot.constants.info.menu import ALL_MENU async def start(update: Update, context: ContextTypes.DEFAULT_TYPE): @@ -16,7 +19,7 @@ async def start(update: Update, context: ContextTypes.DEFAULT_TYPE): async def main_menu(update: Update, context: ContextTypes.DEFAULT_TYPE): - # context.user_data[key.MENU] = ALL_MENU[f"{key.MENU}_MAIN"] + context.user_data[key.MENU] = ALL_MENU[f"{key.MENU}_MAIN"] # uncomment after adding the menu manager await menu(update, context) return state.MAIN_MENU diff --git a/src/bot/conversations/menu_application.py b/src/bot/conversations/menu_application.py index cfc812e..1e17fb0 100644 --- a/src/bot/conversations/menu_application.py +++ b/src/bot/conversations/menu_application.py @@ -1,6 +1,39 @@ -from telegram import Update +from telegram import Update, ReplyKeyboardMarkup, KeyboardButton from telegram.ext import ContextTypes +from src.bot.constants.info.menu import ALL_MENU, MAIN_MENU + async def menu(update: Update, context: ContextTypes.DEFAULT_TYPE): - pass \ No newline at end of file + chat_id = update.message.chat_id + + # Получаем текущее меню пользователя из контекста + current_menu = context.user_data.get('current_menu', 'MENU_MAIN') + + # Получаем информацию о текущем меню + menu_info = ALL_MENU.get(current_menu) + + # Формируем сообщение + message_text = menu_info['DESCRIPTION'] + + # Создаем кнопки на основе дочерних меню + keyboard = [] + for child_menu in menu_info['MENU']: + child_menu_info = ALL_MENU.get(child_menu) + button = KeyboardButton(child_menu_info[key.NAME]) + keyboard.append([button]) + + # Добавляем кнопку "Назад" на основе родительского меню + parent_menu = menu_info.get('PARENT') + if parent_menu: + parent_menu_info = ALL_MENU.get(parent_menu) + back_button = KeyboardButton("Назад") + keyboard.append([back_button]) + + # Формируем и отправляем сообщение с кнопками + reply_markup = ReplyKeyboardMarkup(keyboard, resize_keyboard=True) + await context.bot.send_message( + chat_id=chat_id, + text=message_text, + reply_markup=reply_markup + ) \ No newline at end of file diff --git a/src/bot/core/logger.py b/src/bot/core/logger.py index b6df59d..4dbaa7f 100644 --- a/src/bot/core/logger.py +++ b/src/bot/core/logger.py @@ -1,7 +1,7 @@ import logging.config from pathlib import Path -from bot.core.settings import settings +from src.bot.core.settings import settings BASE_DIR = Path(__file__).resolve().parent.parent diff --git a/src/bot/core/settings.py b/src/bot/core/settings.py index d85f324..73b82db 100644 --- a/src/bot/core/settings.py +++ b/src/bot/core/settings.py @@ -23,4 +23,4 @@ class Config: env_file_encoding = 'utf-8' -settings = Settings() +settings = Settings(telegram_token='6251635925:AAEsD35kpZWb6SWevOGHqVRLkVsW-9Vpkts') diff --git a/src/bot/handlers.py b/src/bot/handlers.py index f99d943..ae7e0ae 100644 --- a/src/bot/handlers.py +++ b/src/bot/handlers.py @@ -1,13 +1,14 @@ from telegram.ext import (CallbackQueryHandler, CommandHandler, ConversationHandler, MessageHandler, filters) -from bot.constants import callback, key, state -from bot.constants.state import MAIN_MENU -from bot.conversations.main_application import main_menu, start, stop +from src.bot.constants import callback, key, state +from src.bot.constants.state import MAIN_MENU +from src.bot.conversations.main_application import main_menu, start, stop -from bot.conversations import form_application -from bot.conversations.main_application import greet_new_member +from src.bot.conversations import form_application +from src.bot.conversations.main_application import greet_new_member +from src.bot.conversations import menu_application form_handler = ConversationHandler( entry_points=[ @@ -46,21 +47,21 @@ main_handler = ConversationHandler( entry_points=[ CommandHandler('start', start), + CallbackQueryHandler(start, pattern='^start$'), ], states={ MAIN_MENU: [ form_handler, - # CallbackQueryHandler( - # menu_application.menu, pattern=fr"^{key.MENU}_\S*$" - # ), - # uncomment after adding the menu manager + CallbackQueryHandler( + menu_application.menu, pattern=fr"^{key.MENU}_\S*$" + ), ], }, fallbacks=[ CommandHandler('menu', main_menu), CommandHandler('stop', stop) ], - allow_reentry=True, + allow_reentry=True ) greet_new_member_handler = MessageHandler( diff --git a/src/bot/utils.py b/src/bot/utils.py index 919fd12..e10fd73 100644 --- a/src/bot/utils.py +++ b/src/bot/utils.py @@ -2,7 +2,7 @@ from email.mime.text import MIMEText from smtplib import SMTP_SSL, SMTPException -from bot.core.settings import settings +from src.bot.core.settings import settings def send_email_message(message: str, subject: str, recipient: str) -> bool: From b82094d2e909339864ed502da81cc227b7672f69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9A=D1=83=D1=80=D0=BA?= =?UTF-8?q?=D0=B8=D0=BD?= Date: Fri, 16 Jun 2023 10:08:48 +0300 Subject: [PATCH 02/12] imports are configured --- src/application.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/application.py b/src/application.py index 56056a1..52457a7 100644 --- a/src/application.py +++ b/src/application.py @@ -1,8 +1,8 @@ from telegram.ext import Application -from src.bot.core import logger # noqa -from src.bot.core.settings import settings -from src.bot.handlers import main_handler, greet_new_member_handler +from bot.core import logger # noqa +from bot.core.settings import settings +from bot.handlers import main_handler, greet_new_member_handler def main() -> None: From 70c5a9bc2055cf41967c79b4fb467eba16959bcf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9A=D1=83=D1=80=D0=BA?= =?UTF-8?q?=D0=B8=D0=BD?= Date: Fri, 16 Jun 2023 10:11:30 +0300 Subject: [PATCH 03/12] added examples of constants --- src/bot/constants/info/menu.py | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/src/bot/constants/info/menu.py b/src/bot/constants/info/menu.py index 7e3f904..263e374 100644 --- a/src/bot/constants/info/menu.py +++ b/src/bot/constants/info/menu.py @@ -1,4 +1,4 @@ -from src.bot.constants import key +from bot.constants import key MAIN_MENU = { @@ -17,26 +17,14 @@ key.NAME: "Кнопка 1", key.DESCRIPTION: "Описание 1", key.PARENT: f"{key.MENU}_MAIN", - key.MENU: [ - f"{key.MENU}_SUB2", - ], }, f"{key.MENU}_SUB2": { key.NAME: "Кнопка 2", key.DESCRIPTION: "Описание 2", key.PARENT: f"{key.MENU}_MAIN", - key.MENU: [ - f"{key.MENU}_SUB3", - ], }, - f"{key.MENU}_SUB3": { - key.NAME: "Назад", - key.DESCRIPTION: "Описание 3", - key.PARENT: f"{key.MENU}_MAIN", - } } - ALL_MENU = { **MAIN_MENU, **SUBMENU, From 909c84b30ef73d6b34702947c76abf49afc11ab0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9A=D1=83=D1=80=D0=BA?= =?UTF-8?q?=D0=B8=D0=BD?= Date: Fri, 16 Jun 2023 10:14:12 +0300 Subject: [PATCH 04/12] added back button text --- src/bot/constants/info/text.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/bot/constants/info/text.py b/src/bot/constants/info/text.py index 53cafaa..fd64ce2 100644 --- a/src/bot/constants/info/text.py +++ b/src/bot/constants/info/text.py @@ -1,6 +1,9 @@ # MAIN MENU START_MESSAGE = 'Здесь должно быть приветственное сообщение (Заглушка)!' +# MAIN +BACK = "Назад" + WELCOME_MESSAGE = ( 'Добро пожаловать {}, в группу по реабилитации ' 'РНИМУ и благотворительного фонда ' From 149c93c7f48805c067a70b9e47ba61a6dc9833a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9A=D1=83=D1=80=D0=BA?= =?UTF-8?q?=D0=B8=D0=BD?= Date: Fri, 16 Jun 2023 10:15:19 +0300 Subject: [PATCH 05/12] add constants --- src/bot/constants/key.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/bot/constants/key.py b/src/bot/constants/key.py index d3f85b2..e23d0a6 100644 --- a/src/bot/constants/key.py +++ b/src/bot/constants/key.py @@ -3,4 +3,3 @@ DESCRIPTION = "DESCRIPTION" ASK = "ASK" PARENT = "PARENT" - From ba1fabe3c931ffb3dd48d3d88dbade60a2ec246d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9A=D1=83=D1=80=D0=BA?= =?UTF-8?q?=D0=B8=D0=BD?= Date: Fri, 16 Jun 2023 10:17:59 +0300 Subject: [PATCH 06/12] uncomment --- src/bot/conversations/main_application.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/bot/conversations/main_application.py b/src/bot/conversations/main_application.py index 257fd94..b38d696 100644 --- a/src/bot/conversations/main_application.py +++ b/src/bot/conversations/main_application.py @@ -2,14 +2,14 @@ from telegram.constants import ParseMode from telegram.ext import ContextTypes, ConversationHandler -from src.bot.constants import state +from bot.constants import state # from bot.constants.info.menu import ALL_MENU # uncomment after adding the menu manager -from src.bot.constants.info.text import START_MESSAGE, STOP_MESSAGE, WELCOME_MESSAGE -from src.bot.conversations.menu_application import menu +from bot.constants.info.text import START_MESSAGE, STOP_MESSAGE, WELCOME_MESSAGE +from bot.conversations.menu_application import menu -from src.bot.constants import key -from src.bot.constants.info.menu import ALL_MENU +from bot.constants import key +from bot.constants.info.menu import ALL_MENU async def start(update: Update, context: ContextTypes.DEFAULT_TYPE): @@ -20,7 +20,6 @@ async def start(update: Update, context: ContextTypes.DEFAULT_TYPE): async def main_menu(update: Update, context: ContextTypes.DEFAULT_TYPE): context.user_data[key.MENU] = ALL_MENU[f"{key.MENU}_MAIN"] - # uncomment after adding the menu manager await menu(update, context) return state.MAIN_MENU @@ -37,4 +36,3 @@ async def stop(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int: """Stops the conversation and replies with the given message.""" await update.message.reply_text(STOP_MESSAGE) return ConversationHandler.END - From 4d38a3698cf144a7763ef8b57c10165fbc646cfa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9A=D1=83=D1=80=D0=BA?= =?UTF-8?q?=D0=B8=D0=BD?= Date: Fri, 16 Jun 2023 10:20:11 +0300 Subject: [PATCH 07/12] added menu function --- src/bot/conversations/menu_application.py | 64 +++++++++++------------ 1 file changed, 30 insertions(+), 34 deletions(-) diff --git a/src/bot/conversations/menu_application.py b/src/bot/conversations/menu_application.py index 1e17fb0..95637e3 100644 --- a/src/bot/conversations/menu_application.py +++ b/src/bot/conversations/menu_application.py @@ -1,39 +1,35 @@ -from telegram import Update, ReplyKeyboardMarkup, KeyboardButton +from telegram import InlineKeyboardButton as Button +from telegram import InlineKeyboardMarkup as Keyboard +from telegram import Update from telegram.ext import ContextTypes -from src.bot.constants.info.menu import ALL_MENU, MAIN_MENU +from bot.constants import key, state +from bot.constants.info import text +from bot.constants.info.menu import ALL_MENU +from bot.utils import send_message async def menu(update: Update, context: ContextTypes.DEFAULT_TYPE): - chat_id = update.message.chat_id - - # Получаем текущее меню пользователя из контекста - current_menu = context.user_data.get('current_menu', 'MENU_MAIN') - - # Получаем информацию о текущем меню - menu_info = ALL_MENU.get(current_menu) - - # Формируем сообщение - message_text = menu_info['DESCRIPTION'] - - # Создаем кнопки на основе дочерних меню - keyboard = [] - for child_menu in menu_info['MENU']: - child_menu_info = ALL_MENU.get(child_menu) - button = KeyboardButton(child_menu_info[key.NAME]) - keyboard.append([button]) - - # Добавляем кнопку "Назад" на основе родительского меню - parent_menu = menu_info.get('PARENT') - if parent_menu: - parent_menu_info = ALL_MENU.get(parent_menu) - back_button = KeyboardButton("Назад") - keyboard.append([back_button]) - - # Формируем и отправляем сообщение с кнопками - reply_markup = ReplyKeyboardMarkup(keyboard, resize_keyboard=True) - await context.bot.send_message( - chat_id=chat_id, - text=message_text, - reply_markup=reply_markup - ) \ No newline at end of file + """Show the selected menu or sub-menu to the user.""" + + callback = update.callback_query + user_data = context.user_data + + if callback and callback.data and callback.data.startswith(key.MENU): + menu = ALL_MENU[callback.data] + user_data[key.MENU] = menu + else: + menu = user_data[key.MENU] + + buttons = [ + [Button(text=ALL_MENU[menu_name][key.NAME], callback_data=menu_name)] + for menu_name in menu.get(key.MENU, []) + ] + if parent_menu := menu.get(key.PARENT): + buttons.append([Button(text=text.BACK, callback_data=parent_menu)]) + + menu_keyboard = Keyboard(buttons) + + await send_message(update, menu[key.DESCRIPTION], keyboard=menu_keyboard) + + return state.MAIN_MENU From f2d297aa181f6adf6430725140cdb6e203717f73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9A=D1=83=D1=80=D0=BA?= =?UTF-8?q?=D0=B8=D0=BD?= Date: Fri, 16 Jun 2023 10:21:42 +0300 Subject: [PATCH 08/12] imports are configured --- src/bot/core/logger.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bot/core/logger.py b/src/bot/core/logger.py index 4dbaa7f..b6df59d 100644 --- a/src/bot/core/logger.py +++ b/src/bot/core/logger.py @@ -1,7 +1,7 @@ import logging.config from pathlib import Path -from src.bot.core.settings import settings +from bot.core.settings import settings BASE_DIR = Path(__file__).resolve().parent.parent From be59182bc467c1b6a5bd00b0805549f95b94a3f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9A=D1=83=D1=80=D0=BA?= =?UTF-8?q?=D0=B8=D0=BD?= Date: Fri, 16 Jun 2023 10:26:07 +0300 Subject: [PATCH 09/12] clean settings --- src/bot/core/settings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bot/core/settings.py b/src/bot/core/settings.py index 73b82db..d85f324 100644 --- a/src/bot/core/settings.py +++ b/src/bot/core/settings.py @@ -23,4 +23,4 @@ class Config: env_file_encoding = 'utf-8' -settings = Settings(telegram_token='6251635925:AAEsD35kpZWb6SWevOGHqVRLkVsW-9Vpkts') +settings = Settings() From b5f8159a3bed3c9a3325c2507accc364ca3d192f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9A=D1=83=D1=80=D0=BA?= =?UTF-8?q?=D0=B8=D0=BD?= Date: Fri, 16 Jun 2023 10:26:58 +0300 Subject: [PATCH 10/12] imports are configured --- src/bot/handlers.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/bot/handlers.py b/src/bot/handlers.py index ae7e0ae..19a1b6e 100644 --- a/src/bot/handlers.py +++ b/src/bot/handlers.py @@ -1,14 +1,14 @@ from telegram.ext import (CallbackQueryHandler, CommandHandler, ConversationHandler, MessageHandler, filters) -from src.bot.constants import callback, key, state -from src.bot.constants.state import MAIN_MENU -from src.bot.conversations.main_application import main_menu, start, stop +from bot.constants import callback, key, state +from bot.constants.state import MAIN_MENU +from bot.conversations.main_application import main_menu, start, stop -from src.bot.conversations import form_application -from src.bot.conversations.main_application import greet_new_member +from bot.conversations import form_application +from bot.conversations.main_application import greet_new_member -from src.bot.conversations import menu_application +from bot.conversations import menu_application form_handler = ConversationHandler( entry_points=[ From 434b229e9f675f803ebfbfbd7f34506dc53d51da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9A=D1=83=D1=80=D0=BA?= =?UTF-8?q?=D0=B8=D0=BD?= Date: Fri, 16 Jun 2023 10:27:47 +0300 Subject: [PATCH 11/12] added send_message function --- src/bot/utils.py | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/src/bot/utils.py b/src/bot/utils.py index e10fd73..dcba164 100644 --- a/src/bot/utils.py +++ b/src/bot/utils.py @@ -2,7 +2,9 @@ from email.mime.text import MIMEText from smtplib import SMTP_SSL, SMTPException -from src.bot.core.settings import settings +from telegram import InlineKeyboardMarkup, Update + +from bot.core.settings import settings def send_email_message(message: str, subject: str, recipient: str) -> bool: @@ -30,3 +32,25 @@ def send_email_message(message: str, subject: str, recipient: str) -> bool: return True except SMTPException: return False + + +async def send_message( + update: Update, + text: str, + keyboard: InlineKeyboardMarkup, + link_preview: bool = False +): + """Send a message to a user using the inline keyboard""" + query = update.callback_query + if query: + await query.answer() + await query.message.edit_text( + text=text, + reply_markup=keyboard, + disable_web_page_preview=not link_preview + ) + await update.message.reply_text( + text=text, + reply_markup=keyboard, + disable_web_page_preview=not link_preview + ) From 9f539f9a01d4fc7ce4eb700fb2a126b777752ad9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9A=D1=83=D1=80=D0=BA?= =?UTF-8?q?=D0=B8=D0=BD?= Date: Fri, 16 Jun 2023 10:36:48 +0300 Subject: [PATCH 12/12] uncomment --- src/bot/conversations/main_application.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/bot/conversations/main_application.py b/src/bot/conversations/main_application.py index b38d696..8c5e0dc 100644 --- a/src/bot/conversations/main_application.py +++ b/src/bot/conversations/main_application.py @@ -2,15 +2,11 @@ from telegram.constants import ParseMode from telegram.ext import ContextTypes, ConversationHandler -from bot.constants import state -# from bot.constants.info.menu import ALL_MENU -# uncomment after adding the menu manager +from bot.constants import state, key +from bot.constants.info.menu import ALL_MENU from bot.constants.info.text import START_MESSAGE, STOP_MESSAGE, WELCOME_MESSAGE from bot.conversations.menu_application import menu -from bot.constants import key -from bot.constants.info.menu import ALL_MENU - async def start(update: Update, context: ContextTypes.DEFAULT_TYPE): """Send a welcome message to the user."""