From 1db524f757c0447967e6257f57d1c9887c740c55 Mon Sep 17 00:00:00 2001 From: Faynot Date: Sat, 28 Mar 2026 21:39:27 +0300 Subject: [PATCH] feat: add create and change profile --- bot.py | 143 ++++++++++++++++++++++++++++++++++++++++++---------- database.py | 23 +++++++-- 2 files changed, 135 insertions(+), 31 deletions(-) diff --git a/bot.py b/bot.py index c64ff55..96dcb14 100644 --- a/bot.py +++ b/bot.py @@ -3,26 +3,29 @@ import logging import sys from os import getenv -from aiogram import Bot, Dispatcher, html +from aiogram import Bot, Dispatcher, html, F from aiogram.client.default import DefaultBotProperties from aiogram.enums import ParseMode -from aiogram.filters import CommandStart -from aiogram.types import Message, InlineKeyboardMarkup, InlineKeyboardButton -from dotenv import load_dotenv -from aiogram import F +from aiogram.filters import CommandStart, Command +from aiogram.types import Message, InlineKeyboardButton, CallbackQuery from aiogram.fsm.context import FSMContext -from aiogram.utils.keyboard import InlineKeyboardBuilder, ReplyKeyboardBuilder +from aiogram.fsm.state import State, StatesGroup +from aiogram.utils.keyboard import InlineKeyboardBuilder +from dotenv import load_dotenv + from database import Database load_dotenv() TOKEN = getenv("BOT_TOKEN") dp = Dispatcher() - db = Database("users.db") -async def on_startup(): - await db.create_tables() - print("db 200") +# Добавили состояние для ручного ввода сферы +class Registration(StatesGroup): + waiting_for_sphere = State() + waiting_for_custom_sphere = State() # <-- Новое состояние + waiting_for_language = State() + waiting_for_preferences = State() @dp.message(CommandStart()) async def command_start_handler(message: Message) -> None: @@ -32,40 +35,124 @@ async def command_start_handler(message: Message) -> None: text = ( "👋 Привет! Я твой персональный агент по Kwork.\n\n" + "💻 ⚠️ ВАЖНО: Этот бот предназначен исключительно для IT-специалистов.\n\n" "🔍 Я мониторю биржу 24/7 и мгновенно присылаю тебе свежие заказы.\n\n" - "⚠️ Нажимая кнопку «Подписаться», вы принимаете условия " + "Нажимая кнопку «Подписаться», вы принимаете условия " "публичной оферты." ) - await message.answer( - text, - reply_markup=builder.as_markup(), - parse_mode="HTML", - disable_web_page_preview=True + await message.answer(text, reply_markup=builder.as_markup(), disable_web_page_preview=True) + +@dp.message(Command("profile")) +async def show_profile(message: Message): + user_data = await db.get_user(message.from_user.id) + + if not user_data or user_data[0] is None: + await message.answer("⚠️ Твой профиль еще не настроен. Нажми /start, чтобы начать.") + return + + sphere, lang, prefs = user_data + + builder = InlineKeyboardBuilder() + builder.row(InlineKeyboardButton(text="📝 Редактировать профиль", callback_data="subscribe")) # Используем тот же callback + + text = ( + "👤 Твой профиль IT-специалиста:\n\n" + f"🌐 Сфера: {sphere}\n" + f"🛠 Стек: {lang}\n" + f"⚙️ Предпочтения: {prefs}\n\n" + "Хочешь что-то изменить? Нажми кнопку ниже." ) + + await message.answer(text, reply_markup=builder.as_markup()) @dp.callback_query(F.data == "subscribe") -async def subscribe_handler(callback: CallbackQuery): - user_id = callback.from_user.id - print("User ID:", user_id) - - await db.add_user(user_id) - - users = await db.get_all() - print("All users in DB:", users) +async def subscribe_handler(callback: CallbackQuery, state: FSMContext): + await db.add_user(callback.from_user.id) + + builder = InlineKeyboardBuilder() + spheres = ["Backend", "Frontend", "Mobile", "DevOps", "Design", "QA"] + for sphere in spheres: + builder.add(InlineKeyboardButton(text=sphere, callback_data=f"sphere_{sphere}")) + + # Добавляем кнопку своего варианта + builder.row(InlineKeyboardButton(text="⌨️ Свой вариант", callback_data="sphere_other")) + builder.adjust(2) await callback.message.edit_text( - "✅ Вы успешно подписались на уведомления!", - parse_mode="HTML" + "Отлично! Давай настроим профиль.\nВ какой сфере IT ты работаешь?", + reply_markup=builder.as_markup() ) - await callback.answer("Подписка активирована!") + await state.set_state(Registration.waiting_for_sphere) + await callback.answer() + +@dp.callback_query(Registration.waiting_for_sphere) +async def sphere_chosen(callback: CallbackQuery, state: FSMContext): + sphere = callback.data.split("_")[1] + + if sphere == "other": + await callback.message.edit_text("Напиши свою сферу деятельности (например: Data Science или GameDev):") + await state.set_state(Registration.waiting_for_custom_sphere) + else: + await state.update_data(sphere=sphere) + await callback.message.edit_text( + f"Выбрано: {sphere}\n\nКакой основной язык программирования или стек технологий используешь?" + ) + await state.set_state(Registration.waiting_for_language) + + await callback.answer() + +# Обработчик для текстового ввода своей сферы +@dp.message(Registration.waiting_for_custom_sphere) +async def custom_sphere_input(message: Message, state: FSMContext): + sphere = message.text + await state.update_data(sphere=sphere) + await message.answer( + f"Принято: {sphere}\n\nКакой основной язык программирования или стек технологий используешь?" + ) + await state.set_state(Registration.waiting_for_language) + +@dp.message(Registration.waiting_for_language) +async def language_chosen(message: Message, state: FSMContext): + await state.update_data(language=message.text) + + # Создаем кнопку для пропуска + builder = InlineKeyboardBuilder() + builder.row(InlineKeyboardButton(text="⏩ Пропустить", callback_data="skip_preferences")) + + await message.answer( + "Принято! И последнее: напиши свои предпочтения по заказам (фильтры).\n" + "Например: 'чек от 5000р' или 'без правок'.\n\n" + "Если не хочешь заполнять сейчас, нажми кнопку ниже.", + reply_markup=builder.as_markup() + ) + await state.set_state(Registration.waiting_for_preferences) + +@dp.callback_query(Registration.waiting_for_preferences, F.data == "skip_preferences") +async def skip_preferences(callback: CallbackQuery, state: FSMContext): + await state.update_data(preferences="Не указано") # Устанавливаем значение по умолчанию + user_data = await state.get_data() + + await db.update_user_data(callback.from_user.id, user_data) + + await callback.message.edit_text( + "✅ Профиль успешно настроен! (Фильтры пропущены)\n\n" + f"Сфера: {user_data['sphere']}\n" + f"Стек: {user_data['language']}\n" + f"Фильтры: {user_data['preferences']}" + ) + await state.clear() + await callback.answer() + +async def on_startup(): + await db.create_tables() + print("Database ready") async def main() -> None: bot = Bot(token=TOKEN, default=DefaultBotProperties(parse_mode=ParseMode.HTML)) dp.startup.register(on_startup) await dp.start_polling(bot) - if __name__ == "__main__": logging.basicConfig(level=logging.INFO, stream=sys.stdout) asyncio.run(main()) diff --git a/database.py b/database.py index 149e53a..6d47c68 100644 --- a/database.py +++ b/database.py @@ -9,7 +9,10 @@ class Database: await db.execute(""" CREATE TABLE IF NOT EXISTS users ( id INTEGER PRIMARY KEY, - user_id INTEGER UNIQUE + user_id INTEGER UNIQUE, + sphere TEXT, + language TEXT, + preferences TEXT ) """) await db.commit() @@ -22,8 +25,22 @@ class Database: ) await db.commit() + async def update_user_data(self, user_id: int, data: dict): + async with aiosqlite.connect(self.db_path) as db: + await db.execute( + "UPDATE users SET sphere = ?, language = ?, preferences = ? WHERE user_id = ?", + (data.get('sphere'), data.get('language'), data.get('preferences'), user_id) + ) + await db.commit() + async def get_all(self): async with aiosqlite.connect(self.db_path) as db: async with db.execute("SELECT * FROM users") as cursor: - rows = await cursor.fetchall() - return rows + return await cursor.fetchall() + async def get_user(self, user_id: int): + async with aiosqlite.connect(self.db_path) as db: + async with db.execute( + "SELECT sphere, language, preferences FROM users WHERE user_id = ?", + (user_id,) + ) as cursor: + return await cursor.fetchone()