updated vers
This commit is contained in:
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
venv
|
||||
bot*.py
|
||||
.env
|
||||
183
main.py
Normal file
183
main.py
Normal file
@@ -0,0 +1,183 @@
|
||||
import os
|
||||
import logging
|
||||
from aiogram import Bot, Dispatcher, Router, types, F
|
||||
from aiogram.filters import CommandStart, StateFilter
|
||||
from aiogram.fsm.state import StatesGroup, State
|
||||
from aiogram.fsm.context import FSMContext
|
||||
from aiogram.types import ReplyKeyboardMarkup, KeyboardButton
|
||||
from dotenv import load_dotenv
|
||||
import kanboard
|
||||
|
||||
# Логирование
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
|
||||
# Загрузка токена из .env
|
||||
load_dotenv()
|
||||
BOT_TOKEN = os.getenv("TELEGRAM_TOKEN")
|
||||
KB_URI = os.getenv("KB_URI")
|
||||
BOT_LOGIN = os.getenv("BOT_LOGIN")
|
||||
BOT_PASS = os.getenv("BOT_PASS")
|
||||
|
||||
bot = Bot(token=BOT_TOKEN)
|
||||
dp = Dispatcher()
|
||||
router = Router()
|
||||
|
||||
# Kanboard client (укажи свои адрес и логин/пароль)
|
||||
kb_connect = "http://"+KB_URI+"/jsonrpc.php"
|
||||
kb = kanboard.Client(kb_connect,BOT_LOGIN, BOT_PASS)
|
||||
|
||||
# FSM состояния
|
||||
class ProjectStates(StatesGroup):
|
||||
waiting_project_choice = State()
|
||||
project_menu = State()
|
||||
waiting_for_task_title = State()
|
||||
|
||||
# /start — главное меню
|
||||
@router.message(CommandStart())
|
||||
async def start(msg: types.Message, state: FSMContext):
|
||||
keyboard = ReplyKeyboardMarkup(
|
||||
keyboard=[[KeyboardButton(text="Список проектов")]],
|
||||
resize_keyboard=True
|
||||
)
|
||||
await msg.answer(
|
||||
"Добро пожаловать! Выберите действие:",
|
||||
reply_markup=keyboard
|
||||
)
|
||||
await state.clear()
|
||||
|
||||
# Кнопка "Список проектов"
|
||||
@router.message(F.text == "Список проектов")
|
||||
async def show_projects(msg: types.Message, state: FSMContext):
|
||||
try:
|
||||
projects = kb.get_my_projects()
|
||||
await state.update_data(projects=projects)
|
||||
except Exception as e:
|
||||
await msg.answer(f"Ошибка получения проектов: {e}")
|
||||
return
|
||||
|
||||
# Список проектов с номерами
|
||||
lines = [f"{idx + 1}. {proj['name']}" for idx, proj in enumerate(projects)]
|
||||
text = "Выберите проект (отправьте его номер):\n" + "\n".join(lines)
|
||||
await msg.answer(text)
|
||||
await state.set_state(ProjectStates.waiting_project_choice)
|
||||
|
||||
# Выбор проекта по номеру
|
||||
@router.message(StateFilter(ProjectStates.waiting_project_choice), F.text)
|
||||
async def project_chosen(msg: types.Message, state: FSMContext):
|
||||
data = await state.get_data()
|
||||
projects = data.get("projects", [])
|
||||
|
||||
# Проверяем, что введено число
|
||||
try:
|
||||
idx = int(msg.text.strip()) - 1
|
||||
except ValueError:
|
||||
await msg.answer("Пожалуйста, введите номер проекта.")
|
||||
return
|
||||
|
||||
if not (0 <= idx < len(projects)):
|
||||
await msg.answer("Нет проекта с таким номером. Попробуйте ещё раз.")
|
||||
return
|
||||
|
||||
selected = projects[idx]
|
||||
await state.update_data(selected_project=selected)
|
||||
keyboard = ReplyKeyboardMarkup(
|
||||
keyboard=[
|
||||
[KeyboardButton(text="Список задач")],
|
||||
[KeyboardButton(text="Добавить задачу")],
|
||||
[KeyboardButton(text="Назад")],
|
||||
],
|
||||
resize_keyboard=True
|
||||
)
|
||||
await msg.answer(
|
||||
f"Вы выбрали проект: {selected['name']}\nВыберите действие:",
|
||||
reply_markup=keyboard
|
||||
)
|
||||
await state.set_state(ProjectStates.project_menu)
|
||||
|
||||
# Кнопка "Список задач"
|
||||
@router.message(StateFilter(ProjectStates.project_menu), F.text == "Список задач")
|
||||
async def show_tasks(msg: types.Message, state: FSMContext):
|
||||
data = await state.get_data()
|
||||
project = data.get("selected_project")
|
||||
if not project:
|
||||
await msg.answer("Ошибка: проект не выбран.")
|
||||
return
|
||||
try:
|
||||
tasks = kb.get_all_tasks(project_id=project['id'])
|
||||
if not tasks:
|
||||
await msg.answer("В этом проекте нет задач.")
|
||||
else:
|
||||
text = "\n".join([
|
||||
f"{t['title']}"
|
||||
for t in tasks
|
||||
])
|
||||
await msg.answer(f"Текущие задачи:\n{text}")
|
||||
except Exception as e:
|
||||
await msg.answer(f"Ошибка получения задач: {e}")
|
||||
|
||||
# Кнопка "Добавить задачу"
|
||||
@router.message(StateFilter(ProjectStates.project_menu), F.text == "Добавить задачу")
|
||||
async def add_task(msg: types.Message, state: FSMContext):
|
||||
await msg.answer("Напишите название задачи одним сообщением:")
|
||||
await state.set_state(ProjectStates.waiting_for_task_title)
|
||||
|
||||
# Кнопка "Назад" — возвращает к выбору проекта по номеру
|
||||
@router.message(StateFilter(ProjectStates.project_menu), F.text == "Назад")
|
||||
async def go_back_to_projects(msg: types.Message, state: FSMContext):
|
||||
data = await state.get_data()
|
||||
projects = data.get("projects", [])
|
||||
if not projects:
|
||||
# если вдруг projects нет в state (например, после сброса)
|
||||
try:
|
||||
projects = kb.get_my_projects()
|
||||
await state.update_data(projects=projects)
|
||||
except Exception as e:
|
||||
await msg.answer(f"Ошибка получения проектов: {e}")
|
||||
return
|
||||
|
||||
lines = [f"{idx + 1}. {proj['name']}" for idx, proj in enumerate(projects)]
|
||||
text = "Выберите проект (отправьте его номер):\n" + "\n".join(lines)
|
||||
await state.update_data(selected_project=None)
|
||||
keyboard = ReplyKeyboardMarkup(
|
||||
keyboard=[[KeyboardButton(text="Список проектов")]],
|
||||
resize_keyboard=True
|
||||
)
|
||||
await msg.answer(
|
||||
text,
|
||||
reply_markup=keyboard
|
||||
)
|
||||
await state.set_state(ProjectStates.waiting_project_choice)
|
||||
|
||||
|
||||
# Принимаем название задачи и создаём её
|
||||
@router.message(StateFilter(ProjectStates.waiting_for_task_title), F.text)
|
||||
async def task_title_received(msg: types.Message, state: FSMContext):
|
||||
data = await state.get_data()
|
||||
project = data.get("selected_project")
|
||||
title = msg.text
|
||||
try:
|
||||
kb.create_task(project_id=project['id'], title=title)
|
||||
await msg.answer(f"Задача '{title}' добавлена!")
|
||||
except Exception as e:
|
||||
await msg.answer(f"Ошибка добавления задачи: {e}")
|
||||
# Меню проекта после добавления задачи
|
||||
keyboard = ReplyKeyboardMarkup(
|
||||
keyboard=[
|
||||
[KeyboardButton(text="Список задач")],
|
||||
[KeyboardButton(text="Добавить задачу")],
|
||||
[KeyboardButton(text="Назад")],
|
||||
],
|
||||
resize_keyboard=True
|
||||
)
|
||||
await msg.answer("Выберите действие:", reply_markup=keyboard)
|
||||
await state.set_state(ProjectStates.project_menu)
|
||||
|
||||
# Регистрация роутера
|
||||
dp.include_router(router)
|
||||
|
||||
async def main():
|
||||
await dp.start_polling(bot)
|
||||
|
||||
if __name__ == "__main__":
|
||||
import asyncio
|
||||
asyncio.run(main())
|
||||
Reference in New Issue
Block a user