From e08116ae07bd06e0d201210fd074ccba78eaad7c Mon Sep 17 00:00:00 2001 From: UdoChudo Date: Mon, 3 Feb 2025 21:51:26 +0500 Subject: [PATCH] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8=D0=BB=20?= =?UTF-8?q?=D1=84=D1=83=D0=BD=D0=BA=D1=86=D0=B8=D1=8E=20=D0=BF=D0=B5=D1=80?= =?UTF-8?q?=D0=B5=D0=BF=D0=B8=D1=81=D0=B8=20=D0=BD=D0=B0=D1=81=D0=B5=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 2 + .idea/.gitignore | 14 ------ Dockerfile | 7 +-- main.py | 118 +++++++++++++++++++++++++++++++++++++++-------- requirements.txt | 17 ++++--- 5 files changed, 116 insertions(+), 42 deletions(-) create mode 100644 .gitignore delete mode 100644 .idea/.gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8e906df --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/.idea/ +users.txt diff --git a/.idea/.gitignore b/.idea/.gitignore deleted file mode 100644 index 4a75283..0000000 --- a/.idea/.gitignore +++ /dev/null @@ -1,14 +0,0 @@ -# Default ignored files -/shelf/ -/workspace.xml -# Editor-based HTTP Client requests -/httpRequests/ -# Datasource local storage ignored files -/dataSources/ -/dataSources.local.xml -.idea/ -/.env -/misc.xml -/vcs.xml -/tgo-bot.iml -/modules.xml diff --git a/Dockerfile b/Dockerfile index 09c4e4d..6d030fc 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # Используем официальный Python образ в качестве базового -FROM python:3.11-slim +FROM python:3.13.1-slim LABEL authors="UdoChudo" @@ -11,12 +11,13 @@ COPY requirements.txt . # Устанавливаем зависимости RUN pip install --no-cache-dir -r requirements.txt - +RUN mkdir /app/data # Копируем все файлы проекта в рабочую директорию COPY main.py . # Устанавливаем переменную окружения для токена API ENV BOT_TOKEN=your_api_token_here - +ENV CAT_TOKEN=your_cat_token_here +ENV DOG_TOKEN=your_dog_token_here # Команда для запуска бота CMD ["python", "main.py"] diff --git a/main.py b/main.py index cb5feda..3f600dd 100644 --- a/main.py +++ b/main.py @@ -1,30 +1,59 @@ +import os import logging import requests -from aiogram import Bot, Dispatcher, types +from aiogram import Bot, Dispatcher, types, BaseMiddleware from aiogram.filters import Command -from aiogram.types import Message +from aiogram.types import Message, InputFile, FSInputFile +from aiogram.types import InlineKeyboardButton, InlineKeyboardMarkup from dotenv import load_dotenv -import os import asyncio - # Загрузка переменных окружения из .env файла load_dotenv() # Получение токена из переменной окружения -BOT_TOKEN = os.getenv("BOT_TOKEN") +BOT_TOKEN = os.getenv('BOT_TOKEN') LOG_LEVEL = os.getenv("LOG_LEVEL") -API_TOKEN_CATS = os.getenv("CATS_TOKEN") -API_TOKEN_DOGS = os.getenv("DOGS_TOKEN") -if not BOT_TOKEN: - raise ValueError("No BOT_TOKEN provided. Please set the API_TOKEN environment variable.") - +CAT_API = os.getenv('CAT_TOKEN') +DOG_API = os.getenv('DOG_TOKEN') +BOT_OWNER_ID = os.getenv('BOT_OWNER') +if not API_TOKEN: + raise ValueError("No API_TOKEN provided. Please set the API_TOKEN environment variable.") +if not CAT_API: + raise ValueError("No CAT_TOKEN provided. Please set the CAT_TOKEN environment variable.") +if not DOG_API: + raise ValueError("No DOG_TOKEN provided. Please set the DOG_TOKEN environment variable.") +if not BOT_OWNER_ID: + raise ValueError("No BOT_OWNER_ID provided. Please set the BOT_OWNER_ID environment variable.") +FILE_PATH = "/app/data/users.txt" +FILE_PATH_WINDOWS = "./users.txt" # Настраиваем логирование -logging.basicConfig(level=logging.ERROR) +logging.basicConfig(level=logging.INFO) # Инициализация бота bot = Bot(token=BOT_TOKEN) dp = Dispatcher() +# Middleware для ограничения частоты запросов +class ThrottlingMiddleware(BaseMiddleware): + def __init__(self, rate_limit=1.0): + self.rate_limit = rate_limit + self.last_time = {} + super().__init__() + + async def __call__(self, handler, event, data): + if isinstance(event, types.Message): + user_id = event.from_user.id + now = asyncio.get_event_loop().time() + if user_id in self.last_time and now - self.last_time[user_id] < self.rate_limit: + await event.answer("Подождите немного перед повторным нажатием!") + return + self.last_time[user_id] = now + return await handler(event, data) + +# Регистрируем middleware +dp.message.middleware(ThrottlingMiddleware()) + + # Обработчик команды /boobs @dp.message(Command(commands=['boobs'], prefix="!/")) async def send_boobs(message: Message): @@ -83,7 +112,7 @@ async def send_butts(message: Message): @dp.message(Command(commands=['cats'], prefix="!/")) async def send_cats(message: Message): - response = requests.get('https://api.thecatapi.com/api/images/get?api_key=API_TOKEN_CATS&format=json') + response = requests.get('https://api.thecatapi.com/api/images/get?api_key=' + CAT_API + '&format=json') if response.status_code == 200: data = response.json() if data: @@ -101,7 +130,7 @@ async def send_cats(message: Message): @dp.message(Command(commands=['dogs'], prefix="!/")) async def send_dogs(message: Message): - response = requests.get('https://api.thedogapi.com/api/images/get?api_key=API_TOKEN_DOGS&format=json') + response = requests.get('https://api.thedogapi.com/api/images/get?api_key=' + DOG_API + '&format=json') if response.status_code == 200: data = response.json() if data: @@ -116,17 +145,68 @@ async def send_dogs(message: Message): await message.answer("Не удалось получить данные с сервера.") else: await message.answer("Ошибка при выполнении запроса к API.") + +@dp.message(Command("census")) +async def start_census(message: types.Message): + if message.from_user.id != int(BOT_OWNER_ID): # Убедитесь, что BOT_OWNER_ID это строка, конвертируем в int + await message.answer("Только владелец бота может запускать перепись!") + return + + # Исправленное создание клавиатуры + keyboard = InlineKeyboardMarkup(inline_keyboard=[ + [InlineKeyboardButton(text="Принять участие", callback_data="census_join")] + ]) + + await message.answer("Перепись участников начата! Нажмите кнопку ниже, чтобы участвовать.", reply_markup=keyboard) + + + +@dp.callback_query(lambda c: c.data == "census_join") +async def register_user(callback_query: types.CallbackQuery): + user = callback_query.from_user + chat_id = callback_query.message.chat.id + username = user.username or user.full_name + + try: + with open("/app/data/users.txt", "r", encoding="utf-8") as file: + existing_users = file.readlines() + except FileNotFoundError: + existing_users = [] + + user_entry = f"{user.id}, @{username}\n" + if user_entry in existing_users: + await callback_query.answer("Вы уже записаны в перепись!") + return + + with open("/app/data/users.txt", "a", encoding="utf-8") as file: + file.write(user_entry) + + await callback_query.answer("Вы записаны в перепись!") + +# Обработчик команды /sendfile +@dp.message(Command(commands=["sendfile"])) +async def send_file(message: Message): + document = "" + # Проверка, является ли отправитель владельцем бота + if message.from_user.id != int(BOT_OWNER_ID): + await message.answer("Только владелец бота может отправить файл!") + return + if os.path.exists(FILE_PATH): + document = FSInputFile(FILE_PATH) + elif os.path.exists(FILE_PATH_WINDOWS): + document = FSInputFile(FILE_PATH_WINDOWS) + else: + await message.answer("Файл не найден на сервере") + await bot.send_document(message.chat.id, document, caption="Вот ваш файл!") + + @dp.message() async def default_message(message: types.Message): pass -async def main(): - # Регистрация обработчиков - dp.message.register(send_boobs) - dp.message.register(send_butts) - dp.message.register(send_cats) - dp.message.register(send_dogs) + +async def main(): # Запуск polling await dp.start_polling(bot) diff --git a/requirements.txt b/requirements.txt index 8a6d288..72321b6 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,20 +1,25 @@ -aiofiles==23.2.1 -aiogram==3.12.0 +aio-pika==9.5.4 +aiofiles==24.1.0 +aiogram==3.17.0 aiohappyeyeballs==2.4.0 -aiohttp==3.10.5 +aiohttp==3.11.11 +aiormq==6.8.1 aiosignal==1.3.1 annotated-types==0.7.0 attrs==24.2.0 certifi==2024.8.30 charset-normalizer==3.3.2 +exceptiongroup==1.2.2 frozenlist==1.4.1 idna==3.8 magic-filter==1.0.12 multidict==6.0.5 -pydantic==2.8.2 -pydantic_core==2.20.1 +pamqp==3.3.0 +propcache==0.2.1 +pydantic==2.10.6 +pydantic_core==2.27.2 python-dotenv==1.0.1 requests==2.32.3 typing_extensions==4.12.2 urllib3==2.2.2 -yarl==1.9.7 +yarl==1.18.3