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
22 changes: 18 additions & 4 deletions telegram_bot_project/bot/commands.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
from typing import Any
from aiogram import types
from aiogram.fsm.context import FSMContext

from messages import MESSAGES
from service.user import UserService
from bot.buttons import get_language_keyboard, menu_reply_keyboard
from states import DialogStates


# Start Command Handler
async def start_command(message: types.Message):
Expand Down Expand Up @@ -36,7 +40,7 @@ async def language_command(message: types.Message):
user_find = 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[language]['AUTHORIZATION_PROBLEM'])
await message.answer(MESSAGES['ENGLISH']['AUTHORIZATION_PROBLEM'])
else:
keyboard = get_language_keyboard()
await message.answer(MESSAGES[language]['LANGUAGE_ASK'], reply_markup=keyboard)
Expand All @@ -47,10 +51,20 @@ async def menu_command(message: types.Message):
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[language]['AUTHORIZATION_PROBLEM'])
await message.answer(MESSAGES['ENGLISH']['AUTHORIZATION_PROBLEM'])
else:
await message.answer(MESSAGES[language]['MENU_MSG'], reply_markup=menu_reply_keyboard())

# Idea Command Handler
async def idea_command(message: types.Message):
pass
async def idea_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)

print(f"--[INFO] - User with id: {user_id} - opened /idea.")
if not user_find:
await message.answer(MESSAGES['ENGLISH']['AUTHORIZATION_PROBLEM'])
else:
await message.answer(MESSAGES[language]['IDEA_RESPONSE'])
await state.set_state(DialogStates.waiting_for_idea)

29 changes: 29 additions & 0 deletions telegram_bot_project/bot/handlers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
from aiogram.fsm.context import FSMContext
from aiogram.types import Message

from bot.buttons import 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:
user_id = message.from_user.id
user_name = message.from_user.username or "unknown"

user_find = await UserService.get_user_by_id(user_id)
if not user_find or not user_find.get("id"):
await message.answer(MESSAGES["ENGLISH"]['AUTHORIZATION_PROBLEM'])
return

language = await UserService.get_user_language(user_id)
idea = message.text

print(f"--[INFO] User with id: {user_id} - provide idea.")
try:
await IdeaService.create_user_idea(user_id, idea)
print(f"--[INFO] - User {user_id} ({user_name}) saved idea: {idea}")
await message.answer(MESSAGES[language]['IDEA_SAVED'], reply_markup=menu_reply_keyboard())
await state.clear()
except Exception as e:
print(f"[ERROR] Saving idea failed: {e}")
await message.answer(MESSAGES[language].get('ERROR_SAVING_IDEA', 'Ошибка при сохранении идеи. Попробуйте позже.'))
2 changes: 2 additions & 0 deletions telegram_bot_project/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from dotenv import load_dotenv
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession
from sqlalchemy.orm import sessionmaker
from contextlib import asynccontextmanager

load_dotenv()

Expand All @@ -19,6 +20,7 @@
def get_token() -> str:
return TOKEN

@asynccontextmanager
async def get_session() -> AsyncSession:
async with async_session() as session:
yield session
23 changes: 19 additions & 4 deletions telegram_bot_project/main.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
import asyncio
from aiogram import Dispatcher, Bot
from aiogram import Dispatcher, Bot, F
from aiogram.filters import Command
from aiogram.fsm.context import FSMContext
from aiogram.fsm.storage.memory import MemoryStorage
from aiogram.types import Message, CallbackQuery
from config import TOKEN
from bot.commands import start_command, help_command, menu_command, language_command
from bot.commands import start_command, help_command, menu_command, language_command, idea_command
from bot.handlers import process_idea_save
from bot.callbacks import start_callback_language
from states import DialogStates

dp = Dispatcher(storage=MemoryStorage())
storage: MemoryStorage = MemoryStorage()
dp = Dispatcher(storage=storage)

# Command Handlers
@dp.message(Command("start"))
Expand All @@ -26,10 +30,21 @@ async def menu(message: Message):
async def language(message: Message):
await language_command(message)

@dp.callback_query(lambda c: c.data in ["lang_ua", "lang_en"])
@dp.message(Command("idea"))
async def idea(message: Message, state: FSMContext):
await idea_command(message, state)

@dp.callback_query(F.data.in_({"lang_ua", "lang_en"}))
async def callback_language(callback_query: CallbackQuery):
await start_callback_language(callback_query)

@dp.message()
async def process_idea_fallback(message: Message, state: FSMContext):
current_state = await state.get_state()
print(f"[DEBUG] Current state: {current_state}")
if current_state == DialogStates.waiting_for_idea.state:
await process_idea_save(message, state)

# Main Function
async def main():
bot = Bot(token=TOKEN)
Expand Down
2 changes: 2 additions & 0 deletions telegram_bot_project/messages.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"SETTINGS_RESPONSE": "🔧 Відкриваю налаштування...",
"MYDAY_RESPONSE": "📅 Ось ваш план на сьогодні...",
"IDEA_RESPONSE": "💡 Поділіться своєю ідеєю, я все запишу!",
"IDEA_SAVED": "💡 Ідея успішно збережена.",
"ADD_TASK_RESPONSE": "📝 Створюємо нову задачу...",
"LANGUAGE_ASK": (
"🌐 **Оберіть мову інтерфейсу:**\n"
Expand All @@ -37,6 +38,7 @@
"SETTINGS_RESPONSE": "🔧 Opening your settings...",
"MYDAY_RESPONSE": "📅 Here’s your plan for today...",
"IDEA_RESPONSE": "💡 Tell me your idea, I’ll save it for you!",
"IDEA_SAVED": "💡 Idea saved successfully.",
"ADD_TASK_RESPONSE": "📝 Creating a new task...",
"LANGUAGE_ASK": (
"🌐 **Choose your language:**\n"
Expand Down
61 changes: 59 additions & 2 deletions telegram_bot_project/service/idea.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,63 @@
from sqlalchemy import text
from config import get_session

# Must implement later :)
class IdeaService:
pass
@staticmethod
async def create_user_idea(user_id: int, idea_name: str) -> int:
async with get_session() as session:
query = text("""
INSERT INTO ideas (user_id, idea_name)
VALUES (:user_id, :idea_name)
RETURNING id
""")
result = await session.execute(query, {
"user_id": user_id,
"idea_name": idea_name
})
await session.commit()
return result.scalar()

@staticmethod
async def update_user_idea(idea_id: int, new_name: str) -> None:
async with get_session() as session:
query = text("""
UPDATE ideas
SET idea_name = :new_name
WHERE id = :idea_id
""")
await session.execute(query, {
"idea_id": idea_id,
"new_name": new_name
})
await session.commit()

@staticmethod
async def delete_user_idea(idea_id: int) -> None:
async with get_session() as session:
query = text("""
DELETE FROM ideas
WHERE id = :idea_id
""")
await session.execute(query, {"idea_id": idea_id})
await session.commit()

@staticmethod
async def get_all_ideas_by_user_id(user_id: int) -> list[dict]:
async with get_session() as session:
query = text("""
SELECT id, idea_name, creation_date
FROM ideas
WHERE user_id = :user_id
ORDER BY creation_date DESC
""")
result = await session.execute(query, {"user_id": user_id})
rows = result.fetchall()
ideas = [
{
"id": row.id,
"idea_name": row.idea_name,
"creation_date": row.creation_date
}
for row in rows
]
return ideas
35 changes: 15 additions & 20 deletions telegram_bot_project/service/task.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
class TaskService:
@staticmethod
async def create_task(user_id: int, task_name: str, task_status: bool = False, start_time: Optional[datetime] = None) -> int:
async for session in get_session():
async with get_session() as session:
result: Any = await session.execute(
text(
"""
Expand All @@ -25,11 +25,10 @@ async def create_task(user_id: int, task_name: str, task_status: bool = False, s
task_id: int = result.scalar_one()
await session.commit()
return task_id
return None

@staticmethod
async def get_task_by_id(task_id: int) -> Optional[dict]:
async for session in get_session():
async with get_session() as session:
result: Any = await session.execute(
text(
"""
Expand All @@ -40,7 +39,7 @@ async def get_task_by_id(task_id: int) -> Optional[dict]:
),
{"task_id": task_id}
)
task: int = result.fetchone()
task = result.fetchone()
if task:
return {
"id": task.id,
Expand All @@ -51,11 +50,10 @@ async def get_task_by_id(task_id: int) -> Optional[dict]:
"creation_date": task.creation_date
}
return None
return None

@staticmethod
async def get_user_tasks(user_id: int) -> List[dict]:
async for session in get_session():
async with get_session() as session:
result: Any = await session.execute(
text(
"""
Expand All @@ -67,6 +65,7 @@ async def get_user_tasks(user_id: int) -> List[dict]:
),
{"user_id": user_id}
)
tasks = result.fetchall()
return [
{
"id": task.id,
Expand All @@ -76,23 +75,22 @@ async def get_user_tasks(user_id: int) -> List[dict]:
"start_time": task.start_time,
"creation_date": task.creation_date
}
for task in result.fetchall()
for task in tasks
]
return None

@staticmethod
async def update_task(task_id: int, task_name: Optional[str] = None,
status: Optional[bool] = None,
start_time: Optional[datetime] = None) -> bool:
async for session in get_session():
status: Optional[bool] = None,
start_time: Optional[datetime] = None) -> bool:
async with get_session() as session:
exists: Any = await session.execute(
text("SELECT 1 FROM tasks WHERE id = :task_id"),
{"task_id": task_id}
)
if not exists.scalar():
return False

update_fields: Any = {}
update_fields: dict = {}
if task_name is not None:
update_fields["task_name"] = task_name
if status is not None:
Expand All @@ -101,7 +99,7 @@ async def update_task(task_id: int, task_name: Optional[str] = None,
update_fields["start_time"] = start_time

if update_fields:
query: Any = text(
query = text(
f"""
UPDATE tasks
SET {', '.join(f'{k} = :{k}' for k in update_fields.keys())}
Expand All @@ -112,11 +110,10 @@ async def update_task(task_id: int, task_name: Optional[str] = None,
await session.execute(query, update_fields)
await session.commit()
return True
return None

@staticmethod
async def delete_task(task_id: int) -> bool:
async for session in get_session():
async with get_session() as session:
result: Any = await session.execute(
text(
"""
Expand All @@ -127,14 +124,13 @@ async def delete_task(task_id: int) -> bool:
),
{"task_id": task_id}
)
deleted: Any = result.scalar_one_or_none()
deleted = result.scalar_one_or_none()
await session.commit()
return deleted is not None
return None

@staticmethod
async def toggle_task_status(task_id: int) -> bool:
async for session in get_session():
async with get_session() as session:
result: Any = await session.execute(
text(
"""
Expand All @@ -146,7 +142,6 @@ async def toggle_task_status(task_id: int) -> bool:
),
{"task_id": task_id}
)
updated: Any = result.scalar_one_or_none()
updated = result.scalar_one_or_none()
await session.commit()
return updated is not None
return None
12 changes: 4 additions & 8 deletions telegram_bot_project/service/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
class UserService:
@staticmethod
async def create_user(user_id: int, user_name: str, language: str = "ENGLISH") -> int:
async for session in get_session():
async with get_session() as session:
result = await session.execute(
text("""
INSERT INTO users (id, user_name, language)
Expand All @@ -16,22 +16,20 @@ async def create_user(user_id: int, user_name: str, language: str = "ENGLISH") -
await session.commit()
inserted_id = result.scalar_one()
return inserted_id
return None

@staticmethod
async def get_user_by_id(user_id: int):
async for session in get_session():
async with get_session() as session:
result = await session.execute(
text("SELECT * FROM users WHERE id = :id"),
{"id": user_id}
)
row = result.first()
return dict(row._mapping) if row else None
return None

@staticmethod
async def update_user_language(user_id: int, new_language: str) -> bool:
async for session in get_session():
async with get_session() as session:
result = await session.execute(
text("""
UPDATE users
Expand All @@ -42,14 +40,12 @@ async def update_user_language(user_id: int, new_language: str) -> bool:
)
await session.commit()
return result.rowcount == 1
return None

@staticmethod
async def get_user_language(user_id: int) -> str:
async for session in get_session():
async with get_session() as session:
result = await session.execute(
text("SELECT language FROM users WHERE id = :id"),
{"id": user_id}
)
return result.scalar_one_or_none()
return None
Loading