diff --git a/.gitignore b/.gitignore index c9d4be3..2a64d84 100644 --- a/.gitignore +++ b/.gitignore @@ -5,7 +5,7 @@ !.vscode/launch.json !.vscode/extensions.json *.code-workspace - +. # Local History for Visual Studio Code .history/ *.app @@ -16,7 +16,8 @@ __pycache__/ *.py[cod] *$py.class - +venv +users.json # C extensions *.so diff --git a/main.py b/main.py new file mode 100644 index 0000000..7536f8c --- /dev/null +++ b/main.py @@ -0,0 +1,204 @@ +#!/usr/bin/env python + +import logging +import os +import json +from datetime import datetime +from typing import Dict +from dotenv import load_dotenv + +from telegram import ReplyKeyboardMarkup, KeyboardButton, Update +from telegram.constants import ParseMode +from telegram.ext import ( + Application, + CommandHandler, + ContextTypes, + MessageHandler, + filters, + CallbackContext, +) + +# Загружаем переменные окружения +load_dotenv() + +TOKEN = os.getenv("TOKEN") +ADMIN_ID = int(os.getenv("ADMIN_ID", "0")) +PASSWORD = os.getenv("PASSWORD", "supersecret") + +USERS_FILE = "users.json" # Файл для хранения пользователей + +# Логирование +logging.basicConfig( + format="%(asctime)s - %(name)s - %(levelname)s - %(message)s", level=logging.INFO +) +logger = logging.getLogger(__name__) + + +def load_users() -> Dict[str, Dict]: + """Загружает список авторизованных пользователей из JSON.""" + if os.path.exists(USERS_FILE): + try: + with open(USERS_FILE, "r", encoding="utf-8") as file: + return json.load(file) + except Exception as e: + logger.error(f"Ошибка загрузки users.json: {e}") + return {} + + +def save_users(users: Dict[str, Dict]) -> None: + """Сохраняет список авторизованных пользователей в JSON.""" + try: + with open(USERS_FILE, "w", encoding="utf-8") as file: + json.dump(users, file, indent=4, ensure_ascii=False) + except Exception as e: + logger.error(f"Ошибка сохранения users.json: {e}") + + +def get_main_menu() -> ReplyKeyboardMarkup: + """Создаёт Reply-клавиатуру для авторизованных пользователей.""" + keyboard = [ + [KeyboardButton("⚙️ Частота вращения"), KeyboardButton("📩 Тест")], + ] + return ReplyKeyboardMarkup(keyboard, resize_keyboard=True) + + +async def start(update: Update, context: CallbackContext) -> None: + """Команда /start — Проверка JSON перед авторизацией.""" + user_id = str(update.effective_user.id) + users = load_users() + + if user_id in users: + await update.message.reply_text( + "✅ Вы уже авторизованы! Выберите действие:", + reply_markup=get_main_menu(), + ) + else: + await update.message.reply_text( + "🚫 Вы не авторизованы. Используйте /password <пароль>." + ) + + +async def handle_buttons(update: Update, context: CallbackContext) -> None: + """Обработчик текстовых кнопок.""" + user_id = str(update.effective_user.id) + users = load_users() + + if user_id not in users: + await update.message.reply_text("🚫 Вы не авторизованы.") + return + + text = update.message.text + + if text == "⚙️ Частота вращения": + await update.message.reply_text("⚙️ Частота вращения: 1500 об/мин") + elif text == "📩 Тест": + await update.message.reply_text("✅ Это тестовое сообщение!") + + +async def password(update: Update, context: CallbackContext) -> None: + """Команда /password <пароль> — Авторизация пользователя.""" + user_id = str(update.effective_user.id) + users = load_users() + + if user_id in users: + await update.message.reply_text("✅ Вы уже авторизованы!") + return + + if len(context.args) != 1: + await update.message.reply_text("❌ Используйте: /password <пароль>") + return + + if context.args[0] == PASSWORD: + first_name = update.effective_user.first_name + last_name = update.effective_user.last_name or "—" + registered_at = datetime.now().strftime("%Y-%m-%d %H:%M:%S") + + users[user_id] = { + "id": user_id, + "first_name": first_name, + "last_name": last_name, + "registered_at": registered_at, + } + save_users(users) # Сохраняем в файл + + await update.message.reply_text( + f"✅ {first_name}, вы авторизованы!", reply_markup=get_main_menu() + ) + + # Уведомляем администратора о новом пользователе + if ADMIN_ID: + try: + await context.bot.send_message( + ADMIN_ID, + f"🔔 Новый пользователь авторизовался:\n" + f"👤 {first_name} {last_name}\n" + f"🆔 ID: {user_id}\n" + f"📅 Дата регистрации: {registered_at}" + ) + except Exception as e: + logger.error(f"Ошибка отправки админу: {e}") + else: + await update.message.reply_text("❌ Неверный пароль.") + + +async def print_users(update: Update, context: CallbackContext) -> None: + """Команда /print_users — Показывает список авторизованных пользователей.""" + user_id = str(update.effective_user.id) + users = load_users() + + if user_id != str(ADMIN_ID): + await update.message.reply_text("⛔ У вас нет доступа к этой команде.") + return + + if not users: + await update.message.reply_text("Нет авторизованных пользователей.") + return + + users_text = "📜 Список авторизованных пользователей:\n\n" + for user in users.values(): + users_text += ( + f"👤 {user['first_name']} {user['last_name']}\n" + f"🆔 ID: {user['id']}\n" + f"📅 Дата регистрации: {user['registered_at']}\n" + f"——————————\n" + ) + + await update.message.reply_text(users_text, parse_mode=ParseMode.HTML) + + +async def help_command(update: Update, context: CallbackContext) -> None: + """Команда /help — выводит список команд.""" + help_text = ( + "🛠 Доступные команды:\n\n" + "/start - Начать работу с ботом\n" + "/password <пароль> - Авторизоваться\n" + "/print_users - Список пользователей (только для админа)\n" + "/help - Справка по командам\n\n" + "⚙️ Также доступны кнопки с действиями!" + ) + await update.message.reply_text(help_text, parse_mode=ParseMode.HTML) + + +def main() -> None: + """Запуск бота.""" + if not TOKEN: + logger.error("❌ Не задан токен!") + return + + application = Application.builder().token(TOKEN).build() + + # Добавление команд + application.add_handler(CommandHandler("start", start)) + application.add_handler(CommandHandler("password", password)) + application.add_handler(CommandHandler("print_users", print_users)) + application.add_handler(CommandHandler("help", help_command)) + + # Обработка нажатий кнопок + application.add_handler(MessageHandler(filters.TEXT & ~filters.COMMAND, handle_buttons)) + + logger.info("🤖 Бот запущен...") + application.run_polling(allowed_updates=Update.ALL_TYPES) + + +if __name__ == "__main__": + main() diff --git a/requrements.txt b/requrements.txt new file mode 100644 index 0000000..72494a3 --- /dev/null +++ b/requrements.txt @@ -0,0 +1,2 @@ +python-telegram-bot-21.10 +python-dotenv-1.0.1