diff --git a/telegram_bot_project/.example.env b/telegram_bot_project/.example.env index 5731708..214309a 100644 --- a/telegram_bot_project/.example.env +++ b/telegram_bot_project/.example.env @@ -1,2 +1,14 @@ +# General Configs BOT_TOKEN=TELEGRAM_BOT_TOKEN -DATABASE_URL=db_driver+asyncpg://username:password@host:port/db_username \ No newline at end of file +DATABASE_URL=db_driver+asyncpg://username:password@host:port/db_username + +# SMTP (Simple Mail Transfer Protocol) Configuration +SMTP_HOST=smtp.example.com +SMTP_PORT=587 +SMTP_USER=user@example.com +SMTP_PASSWORD=Password +SMTP_USE_TLS=True +SMTP_SLL=False +SMTP_MESSAGE_SUBJECT=SUBJECT +SMTP_FROM_EMAIL=user@example.com +SMTP_MESSAGE_RECEIVER=receiver@example.com \ No newline at end of file diff --git a/telegram_bot_project/bot/commands.py b/telegram_bot_project/bot/commands.py index 11a225f..8bdd5ca 100644 --- a/telegram_bot_project/bot/commands.py +++ b/telegram_bot_project/bot/commands.py @@ -403,3 +403,15 @@ async def show_evening_routines(message: types.Message): ) await message.answer(formatted_morning_routine, reply_markup=evening_routine_keyboard()) + +# Send feedback message command +async def send_feedback_command(message: types.Message, state: FSMContext): + user_id: int = message.from_user.id + user_find: Any = await UserService.get_user_by_id(user_id) + language: str = await UserService.get_user_language(user_id) + + if not user_find: + await message.answer(MESSAGES['ENGLISH']['AUTHORIZATION_PROBLEM']) + else: + await message.answer(MESSAGES[language]['SMTP_MESSAGE_TEXT']) + await state.set_state(DialogStates.feedback_message) \ No newline at end of file diff --git a/telegram_bot_project/bot/handlers.py b/telegram_bot_project/bot/handlers.py index 91e33eb..b5481ab 100644 --- a/telegram_bot_project/bot/handlers.py +++ b/telegram_bot_project/bot/handlers.py @@ -1,6 +1,7 @@ from aiogram.fsm.context import FSMContext from aiogram.types import Message, message +from service.smtp import SmtpService from bot.buttons import * from messages import MESSAGES from service.idea import IdeaService @@ -470,4 +471,26 @@ async def process_save_updated_morning_routine(message: Message, state: FSMConte await message.answer(MESSAGES[language]['ROUTINE_NAME_SET'].format(routine_title), reply_markup=routine_keyboard) await state.clear() except: - await message.answer(MESSAGES[language]['ROUTINE_EXISTS'], reply_markup=routine_keyboard) \ No newline at end of file + await message.answer(MESSAGES[language]['ROUTINE_EXISTS'], reply_markup=routine_keyboard) + + +async def process_feedback_message(message: Message, state: FSMContext): + user_id = message.from_user.id + user_find = await UserService.get_user_by_id(user_id) + user_name = message.from_user.username + language = await UserService.get_user_language(user_id) or "ENGLISH" + + if not user_find: + await message.answer(MESSAGES["ENGLISH"]['AUTHORIZATION_PROBLEM']) + return + + feedback_message = message.text.strip() + if not feedback_message: + await message.answer(MESSAGES["ENGLISH"]['INVALID_MESSAGE']) + return + + print("-- [INFO] - Feedback message from user with id: {user_id} is: {feedback_message}") + await SmtpService.send_feedback_message(feedback_message, user_id, user_name) + await message.answer(MESSAGES[language]['SMTP_MESSAGE_SENT'], reply_markup=settings_menu_keyboard()) + await state.clear() + diff --git a/telegram_bot_project/config.py b/telegram_bot_project/config.py index 72d56c7..055e81c 100644 --- a/telegram_bot_project/config.py +++ b/telegram_bot_project/config.py @@ -4,6 +4,7 @@ from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession from sqlalchemy.orm import sessionmaker from contextlib import asynccontextmanager +from dataclasses import dataclass load_dotenv() @@ -27,3 +28,18 @@ def get_token() -> str: async def get_session() -> AsyncSession: async with async_session() as session: yield session + +@dataclass +class SmtpData: + smtp_user: str = os.getenv("SMTP_USER") + smtp_password: str = os.getenv("SMTP_PASSWORD") + smtp_host: str = os.getenv("SMTP_HOST") + smtp_port: int = int(os.getenv("SMTP_PORT")) + smtp_ssl: bool = os.getenv("SMTP_SSL") == "True" + smtp_tsl: bool = os.getenv("SMTP_TLS") == "True" + smtp_from: str = os.getenv("SMTP_USER") + smtp_receiver: str = os.getenv("SMTP_MESSAGE_RECEIVER") + smtp_subject: str = os.getenv("SMTP_MESSAGE_SUBJECT") + +def get_smtp_data() -> SmtpData: + return SmtpData() \ No newline at end of file diff --git a/telegram_bot_project/main.py b/telegram_bot_project/main.py index a262745..0364213 100644 --- a/telegram_bot_project/main.py +++ b/telegram_bot_project/main.py @@ -205,6 +205,14 @@ async def evening_routines_show(message: types.Message): async def morning_routines(message: Message): await show_evening_routines(message) +@dp.message(Command("feedback")) +async def feedback(message: Message, state: FSMContext): + await send_feedback_command(message, state) + +@dp.message(lambda m: m.text == SETTINGS_BUTTON_FEEDBACK) +async def feedback(message: Message, state: FSMContext): + await send_feedback_command(message, state) + @dp.message(lambda m: m.text == ROUTINE_EVENING_VIEW) async def evening_routines_view(message: types.Message): await show_evening_routines(message) @@ -269,6 +277,8 @@ async def process_fallback(message: Message, state: FSMContext): data = await state.get_data() routine_type = data.get("routine_type", "morning") await process_update_morning_routine(message, state, type=routine_type) + elif current_state == DialogStates.feedback_message: + await process_feedback_message(message, state) # Main Function async def main(): diff --git a/telegram_bot_project/messages.py b/telegram_bot_project/messages.py index f8ae06f..9b09693 100644 --- a/telegram_bot_project/messages.py +++ b/telegram_bot_project/messages.py @@ -79,6 +79,9 @@ "ROUTINE_DELETED": "Розпорядок видалено", "NEW_ROUTINE_NAME": "Будь ласка, введи нову назву розпорядку:", "ROUTINE_NAME_SET": "Нову назву розпорядку успішно змінено на «{}».", + "SMTP_MESSAGE_TEXT": "Будь ласка, залиш свій відгук нижче:", + "SMTP_MESSAGE_SENT": "Дякуємо за твій відгук, наша команда перевірить це повідомлення", + "INVALID_MESSAGE": "Будь ласка, введи коректний текст.", "LANGUAGE_ASK": ( "🌐 **Оберіть мову інтерфейсу:**\n" "Натисніть кнопку нижче ⬇️" @@ -157,6 +160,9 @@ "ROUTINE_DELETED": "Routine deleted", "NEW_ROUTINE_NAME": "Please enter the new routine name:", "ROUTINE_NAME_SET": "New routine name successfully set to {}.", + "INVALID_MESSAGE": "Please enter valid text.", + "SMTP_MESSAGE_TEXT": "Please provide your feedback below:", + "SMTP_MESSAGE_SENT": "Thank for your feedback our team will check this message", "ROUTINE_TIME": ( "⏰ Your routine:\n" "• Wake-up time: {}\n" @@ -222,4 +228,20 @@ EVENING_ROUTINE_EDIT_BTN = "✏️ Edit Evening" MY_EVENING_ROUTINE_BTN = "🌙 My Evening Routine" +USER_FEEDBACK_MAIL_TEXT = """ +📬 New User Feedback Received! + +Here’s what the user had to say: + +------------------------ +{feedback} +------------------------ + +🧑‍💻 User Info: +- Username: {username} +- User ID: {user_id} +- Date: {date} + +Please review it and take action if needed. +""" diff --git a/telegram_bot_project/service/smtp.py b/telegram_bot_project/service/smtp.py new file mode 100644 index 0000000..d1ed8bf --- /dev/null +++ b/telegram_bot_project/service/smtp.py @@ -0,0 +1,42 @@ +import aiosmtplib +from datetime import datetime +from email.mime.text import MIMEText +from bot.utills import validate_text +from config import SmtpData, get_smtp_data +from messages import USER_FEEDBACK_MAIL_TEXT + +smtp_data: SmtpData = get_smtp_data() +if not smtp_data: + raise Exception("-- [ERROR] - SMTP data not found.") + +class SmtpService: + @staticmethod + async def send_feedback_message(user_message: str, user_id: int, user_name: str): + if not validate_text(user_message): + print("-- [ERROR] - Invalid message.") + return + + email_body: str = USER_FEEDBACK_MAIL_TEXT.format( + feedback=user_message, + username=user_name, + user_id=user_id, + date=datetime.now().strftime("%Y-%m-%d %H:%M:%S") + ) + + email_message = MIMEText(email_body, "plain") + email_message['Subject'] = smtp_data.smtp_subject + email_message['From'] = smtp_data.smtp_from + email_message['To'] = smtp_data.smtp_receiver + + try: + await aiosmtplib.send( + email_message, + hostname=smtp_data.smtp_host, + port=smtp_data.smtp_port, + start_tls=True, + username=smtp_data.smtp_user, + password=smtp_data.smtp_password, + ) + print("-- [INFO] - Feedback message sent successfully.") + except Exception as e: + print(f"-- [ERROR] - Failed to send feedback message: {e}") diff --git a/telegram_bot_project/states.py b/telegram_bot_project/states.py index e82b777..3c59604 100644 --- a/telegram_bot_project/states.py +++ b/telegram_bot_project/states.py @@ -17,4 +17,5 @@ class DialogStates(StatesGroup): add_morning_routine = State() delete_morning_routine = State() update_morning_routine = State() - update_morning_routine_id = State() \ No newline at end of file + update_morning_routine_id = State() + feedback_message = State() \ No newline at end of file