Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion sql/schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ CREATE TABLE tasks (
CREATE TABLE ideas (
id SERIAL PRIMARY KEY,
user_id BIGINT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
idea_name VARCHAR(255) NOT NULL,
idea_name VARCHAR(255) NOT NULL UNIQUE,
creation_date TIMESTAMP NOT NULL DEFAULT NOW()
);

Expand Down
23 changes: 18 additions & 5 deletions telegram_bot_project/bot/buttons.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,17 @@ def get_language_keyboard() -> InlineKeyboardMarkup:


def menu_reply_keyboard() -> ReplyKeyboardMarkup:
reply_keyboard = ReplyKeyboardMarkup(keyboard=[], resize_keyboard=True, row_width=2)
menu_reply_keyboard = ReplyKeyboardMarkup(keyboard=[], resize_keyboard=True, row_width=2)

button_settings = KeyboardButton(text=BUTTON_SETTINGS)
button_idea = KeyboardButton(text=BUTTON_IDEA)
button_day = KeyboardButton(text=BUTTON_MYDAY)
button_task = KeyboardButton(text=BUTTON_ADD_TASK)

reply_keyboard.keyboard.append([button_settings, button_idea])
reply_keyboard.keyboard.append([button_day, button_task])
menu_reply_keyboard.keyboard.append([button_settings, button_idea])
menu_reply_keyboard.keyboard.append([button_day, button_task])

return reply_keyboard
return menu_reply_keyboard

def get_idea_conf_keyboard() -> InlineKeyboardMarkup:
inline_markup = InlineKeyboardMarkup(inline_keyboard=[], row_width=2)
Expand All @@ -36,4 +36,17 @@ def get_idea_conf_keyboard() -> InlineKeyboardMarkup:
save_button: InlineKeyboardButton = InlineKeyboardButton(text=SAVE_BUTTON, callback_data="save_idea")

inline_markup.inline_keyboard.append([delete_button, save_button])
return inline_markup
return inline_markup

def idea_reply_keyboard() -> ReplyKeyboardMarkup:
idea_reply_keyboard = ReplyKeyboardMarkup(keyboard=[], resize_keyboard=True, row_width=2)

button_menu = KeyboardButton(text=MENU_BUTTON)
button_delete = KeyboardButton(text=DEL_BUTTON)
button_add = KeyboardButton(text=BUTTON_IDEA)
button_all_ideas = KeyboardButton(text=ALL_IDEAS)

idea_reply_keyboard.keyboard.append([button_delete, button_add])
idea_reply_keyboard.keyboard.append([button_menu, button_all_ideas])

return idea_reply_keyboard
10 changes: 5 additions & 5 deletions telegram_bot_project/bot/callbacks.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from aiogram import types
from aiogram.fsm.context import FSMContext

from bot.buttons import menu_reply_keyboard
from bot.buttons import menu_reply_keyboard, idea_reply_keyboard
from messages import MESSAGES
from service.idea import IdeaService
from service.user import UserService
Expand Down Expand Up @@ -53,7 +53,7 @@ async def callback_idea_process(callback_query: types.CallbackQuery, state: FSMC
match callback_query.data:
case "delete_idea":
print(f"--[INFO] - User {user_id} ({user_name}) deleted idea.")
await callback_query.message.answer(MESSAGES[language]["IDEA_DELETE"], reply_markup=menu_reply_keyboard())
await callback_query.message.answer(MESSAGES[language]["IDEA_DELETE"], reply_markup=idea_reply_keyboard())
await state.clear()
case "save_idea":
try:
Expand All @@ -62,16 +62,16 @@ async def callback_idea_process(callback_query: types.CallbackQuery, state: FSMC

if not idea:
print(f"--[INFO] - User {user_id} ({user_name}) sent empty idea.")
await callback_query.message.answer(MESSAGES[language]["IDEA_PROBLEM"], reply_markup=menu_reply_keyboard())
await callback_query.message.answer(MESSAGES[language]["IDEA_PROBLEM"], reply_markup=idea_reply_keyboard())
return
else:
await IdeaService.create_user_idea(user_id, idea)

print(f"--[INFO] - User {user_id} ({user_name}) saved idea: {idea}")
await callback_query.message.answer(MESSAGES[language]["IDEA_SAVED"], reply_markup=menu_reply_keyboard())
await callback_query.message.answer(MESSAGES[language]["IDEA_SAVED"], reply_markup=idea_reply_keyboard())
await state.clear()
except Exception as e:
await callback_query.message.answer(MESSAGES[language]["IDEA_PROBLEM"])
case _:
print(f"--[INFO] - User {user_id} ({user_name}) sent invalid callback: {callback_query.data}")
await callback_query.message.answer(MESSAGES[language]["IDEA_PROBLEM"], reply_markup=menu_reply_keyboard())
await callback_query.message.answer(MESSAGES[language]["IDEA_PROBLEM"], reply_markup=idea_reply_keyboard())
6 changes: 3 additions & 3 deletions telegram_bot_project/bot/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from messages import MESSAGES
from service.idea import IdeaService
from service.user import UserService
from bot.buttons import get_language_keyboard, menu_reply_keyboard
from bot.buttons import get_language_keyboard, menu_reply_keyboard, idea_reply_keyboard
from states import DialogStates

# Start Command Handler
Expand Down Expand Up @@ -88,8 +88,8 @@ async def ideas_command(message: types.Message):
dividers: str = "\n" + ("-" * int(len(MESSAGES[language]['IDEAS_SHOW']) * 1.65))

formatted_ideas = MESSAGES[language]['IDEAS_SHOW'] + dividers + "\n" + "\n".join(
f"# {num}. {idea['idea_name']}\n[{format_date(idea['creation_date'])}]"
f"# {num}. {idea['idea_name']}\n\n - 📅 - [{format_date(idea['creation_date'])}]\n"
for num, idea in enumerate(ideas, start=1)
)

await message.answer(formatted_ideas, reply_markup=menu_reply_keyboard())
await message.answer(formatted_ideas, reply_markup=idea_reply_keyboard())
39 changes: 30 additions & 9 deletions telegram_bot_project/bot/handlers.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
from aiogram.fsm.context import FSMContext
from aiogram.types import Message, InlineKeyboardMarkup
from aiogram.types import Message

from bot.buttons import get_idea_conf_keyboard
from bot.buttons import get_idea_conf_keyboard, menu_reply_keyboard
from messages import MESSAGES
from service.idea import IdeaService
from service.user import UserService

async def process_idea_save(message: Message, state: FSMContext) -> None:
Expand All @@ -12,16 +13,36 @@ async def process_idea_save(message: Message, state: FSMContext) -> None:
await message.answer(MESSAGES["ENGLISH"]['AUTHORIZATION_PROBLEM'])
return

language = await UserService.get_user_language(user_id)
idea = message.text
language = await UserService.get_user_language(user_id) or "ENGLISH"
idea = message.text.strip()

exist = await IdeaService.get_by_idea_name(idea)
if exist:
await message.answer(
MESSAGES[language].get('IDEA_EXIST', "⚠️ This idea already exists."),
reply_markup=menu_reply_keyboard()
)
return

print(f"--[INFO] User with id: {user_id} provided idea.")

print(f"--[INFO] User with id: {user_id} - provide idea.")
try:
await state.update_data(idea=idea)

dividers: str = "\n" + ("-" * int(len(MESSAGES[language]['IDEA_ACTION']) * 1.65))
keyboard: InlineKeyboardMarkup = get_idea_conf_keyboard()
await message.answer(MESSAGES[language]['IDEA_ACTION'] + dividers + f"\nIDEA: {idea}", reply_markup=keyboard)
divider = "\n" + ("-" * int(len(MESSAGES[language]['IDEA_ACTION']) * 1.65))

keyboard = get_idea_conf_keyboard()

await message.answer(
f"{MESSAGES[language]['IDEA_ACTION']}{divider}\n💡 *Idea:* {idea}",
reply_markup=keyboard
)

except Exception as e:
print(f"[ERROR] Saving idea failed: {e}")
await message.answer(MESSAGES[language].get('ERROR_SAVING_IDEA', 'Ошибка при сохранении идеи. Попробуйте позже.'))
await message.answer(
MESSAGES[language].get(
'ERROR_SAVING_IDEA',
"⚠️ Error saving the idea. Please try again later."
)
)
4 changes: 4 additions & 0 deletions telegram_bot_project/messages.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"IDEA_DELETE": "🗑️ Ідею було видалено.",
"IDEA_PROBLEM": "⚠️ Виникла проблема із збереженням ідеї. Спробуйте ще раз.",
"IDEAS_SHOW": "💡 Усі ваші ідеї: ",
"IDEA_EXISTS": "⚠️ Ця ідея вже існує.",
"NO_IDEAS": "📝 Ви ще не маєте ідей.",
"LANGUAGE_ASK": (
"🌐 **Оберіть мову інтерфейсу:**\n"
Expand Down Expand Up @@ -49,6 +50,7 @@
"IDEA_DELETE": "🗑️ Idea has been deleted.",
"IDEA_PROBLEM": "⚠️ There was an issue saving your idea. Please try again.",
"IDEAS_SHOW": "💡 Here are your ideas: ",
"IDEA_EXISTS": "⚠️ This idea already exists",
"NO_IDEAS": "📝 You don't have any ideas yet. Be the first to save one!",
"LANGUAGE_ASK": (
"🌐 **Please choose your interface language:**\n"
Expand All @@ -74,3 +76,5 @@
BUTTON_EN_LANG: str = "🇬🇧 English"
DEL_BUTTON: str = "🗑️ Delete"
SAVE_BUTTON: str = "💾 Save"
MENU_BUTTON: str = "Menu"
ALL_IDEAS: str = "All ideas"
17 changes: 17 additions & 0 deletions telegram_bot_project/service/idea.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from sqlalchemy import text
from typing import Optional
from config import get_session

class IdeaService:
Expand All @@ -17,6 +18,22 @@ async def create_user_idea(user_id: int, idea_name: str) -> int:
await session.commit()
return result.scalar()

@staticmethod
async def get_by_idea_name(idea_name: str) -> Optional[int]:
async with get_session() as session:
query = text(
"""
SELECT id
FROM ideas
WHERE idea_name = :idea_name
"""
)

result = await session.execute(query, {"idea_name": idea_name})
row = result.first()

return row[0] if row else None

@staticmethod
async def update_user_idea(idea_id: int, new_name: str) -> None:
async with get_session() as session:
Expand Down