Compare commits

...

1 Commits
main ... bot

Author SHA1 Message Date
Даня Вакуленков
42f95b6e9d Add bot functional 2024-10-28 00:04:35 +03:00
36 changed files with 522 additions and 0 deletions

BIN
bot/.DS_Store vendored Normal file

Binary file not shown.

21
bot/Dockerfile Normal file
View File

@ -0,0 +1,21 @@
FROM python:3.10.7
# python envs
ENV PYTHONFAULTHANDLER=1 \
PYTHONUNBUFFERED=1 \
PYTHONHASHSEED=random \
PIP_NO_CACHE_DIR=off \
PIP_DISABLE_PIP_VERSION_CHECK=on \
PIP_DEFAULT_TIMEOUT=100
# python dependencies
COPY ./requirements.txt /
RUN pip install -r /requirements.txt
COPY ./scripts/start.sh ./scripts/gunicorn.sh /
RUN chmod +x /start.sh
RUN chmod +x /gunicorn.sh
WORKDIR /app

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
bot/avatar.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

64
bot/back_send.py Normal file
View File

@ -0,0 +1,64 @@
import json
import io
from fastapi import APIRouter, HTTPException, BackgroundTasks
from pydantic import BaseModel
from create_bot import bot, important_message, url
from aiogram import types
from create_bot import request_url, api_token
import requests
import time
import re
from aiogram.types import InlineKeyboardMarkup, InlineKeyboardButton, WebAppInfo, ReplyKeyboardRemove
from loguru import logger
def get_answer_keyboard():
keyboard = InlineKeyboardMarkup()
button1 = InlineKeyboardButton('Главное меню', callback_data='main_menu_text')
keyboard.add(button1)
return keyboard
class AlertSchema(BaseModel):
tg_id: int
message: str
class DispatchSchema(BaseModel):
tg_id: int
text: str
attachment_path: str
button_name: str | None = None
button_url: str | None = None
web_app_button_name: str | None = None
send_message_router = APIRouter(
prefix=''
)
@send_message_router.post('/dispatch/')
async def handle_dispatch(data: DispatchSchema, background_tasks: BackgroundTasks):
try:
media = io.BytesIO(requests.get(data.attachment_path).content)
media.seek(0)
attachment = types.InputFile(media)
keyboard = InlineKeyboardMarkup()
if data.button_name and data.button_url:
button1 = InlineKeyboardButton(f'{data.button_name}', url=f"{data.button_url}")
keyboard.add(button1)
if data.web_app_button_name:
button2 = InlineKeyboardButton(f'{data.web_app_button_name}', web_app=WebAppInfo(url=f"{url}"))
keyboard.add(button2)
if not data.button_name and not data.web_app_button_name:
await bot.send_photo(data.tg_id, attachment, caption=data.text, parse_mode=types.ParseMode.MARKDOWN, reply_markup=ReplyKeyboardRemove())
else:
await bot.send_photo(data.tg_id, attachment, caption=data.text, reply_markup=keyboard, parse_mode=types.ParseMode.MARKDOWN)
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
return {'ok': True}
@send_message_router.post('/alert/')
async def handle_alert(data: AlertSchema):
try:
await bot.send_message(chat_id=data.tg_id, text=data.message, parse_mode=types.ParseMode.MARKDOWN) #, reply_markup=get_answer_keyboard())
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
return {'ok': True}

27
bot/config.py Normal file
View File

@ -0,0 +1,27 @@
import logging
from aiogram import Bot, types
from aiogram import Dispatcher
from create_bot import bot, token, WEBHOOK_URL
from handlers.register_handlers import register_all_handlers
from aiogram.fsm.storage.memory import MemoryStorage
from loguru import logger
dp = Dispatcher(bot, storage=MemoryStorage())
logger.add("logs.log", format = "{time} | {module} : {function} | {level} | {message}", level = "INFO", rotation = "1 week", compression = "zip")#, serialize = True)
async def on_startup():
webhook_info = await bot.get_webhook_info()
if webhook_info.url != WEBHOOK_URL:
await bot.set_webhook(
url=WEBHOOK_URL,
drop_pending_updates=True
)
register_all_handlers(dp)
async def on_shutdown():
await bot.session.close()
await bot.delete_webhook()

24
bot/create_bot.py Normal file
View File

@ -0,0 +1,24 @@
from aiogram import Bot
import os
token = os.getenv('TG_TOKEN', '7748003961:AAEIXu8NFICPabNaQP5JQ3AcY79nZdUbKdI')
api_token = os.getenv('API_TOKEN', 'b43fa8ccea5b6dd5e889a8ad3890ce14ce36a8bc') # TODO: remove
backend_url = os.getenv('BACKEND_URL', 'http://backend:8000')
request_url = f'{backend_url}/api'
url = os.getenv('URL', 'https://google.com')
bot_name = os.getenv('BOT_NAME', 'https://t.me/danyadjan_test_bot')
bucket_name = 'brawny-basket'
username = 'e80165bc-8d55-42a3-a96b-f62314446f87'
password = '0d8e160fc5625ff0f176a0f70a22e336e8fb21a9841a5d20223714b7cee19341'
endpoint_url = 'https://s3.aeza.cloud/brawny-basket'
WEBHOOK_HOST = f'{url}/bot'
WEBHOOK_PATH = 'wh'
WEBHOOK_URL = f'{WEBHOOK_HOST}/{WEBHOOK_PATH}/{token}'
bot = Bot(token=token)
important_message = {}
event_number = {}

1
bot/handlers/__init__.py Normal file
View File

@ -0,0 +1 @@
from cgitb import handler

Binary file not shown.

Binary file not shown.

Binary file not shown.

103
bot/handlers/instruction.py Normal file
View File

@ -0,0 +1,103 @@
from aiogram import types
from aiogram import Bot, Dispatcher
import re
import json
from create_bot import bot, important_message, event_number
from memcached_def import add_rec, get_rec
from aiogram.types import ReplyKeyboardMarkup, KeyboardButton, ReplyKeyboardRemove, InlineKeyboardMarkup, InlineKeyboardButton, FSInputFile
from loguru import logger
def get_event_keyboard(number):
kb = []
dlina = 5
button1 = InlineKeyboardButton(text='', callback_data="num_decr")
button2 = InlineKeyboardButton(text=f'{number + 1}/{dlina}', callback_data="element")
button3 = InlineKeyboardButton(text='', callback_data="num_incr")
button4 = InlineKeyboardButton(text='Главное меню', callback_data='main_menu_delete')
if int(number + 1) == 1:
kb = [[button2, button3]]
elif int(number + 1) == dlina:
kb = [[button1, button2]]
else:
kb = [[button1, button2, button3]]
kb.append([button4])
keyboard = InlineKeyboardMarkup(inline_keyboard=kb)
return keyboard
def read_data_from_file(file_path):
try:
with open(file_path, 'r') as file:
data_lines = file.readlines()
data_dict = {}
for line in data_lines:
key, value = line.strip().split(": ")
data_dict[key.strip()] = value.strip()
return data_dict
except FileNotFoundError:
print("File not found.")
return None
except Exception as e:
print("An error occurred:", e)
return None
def update_file(file_path, data_dict):
try:
with open(file_path, 'r') as file:
existing_data = file.readlines()
with open(file_path, 'w') as file:
for line in existing_data:
key = line.split(":")[0].strip()
if key in data_dict:
file.write(f"{key}: {data_dict[key]}\n")
else:
file.write(line)
for key, value in data_dict.items():
if key not in existing_data:
file.write(f"{key}: {value}\n")
# print("File updated successfully.")
except Exception as e:
print("An error occurred:", e)
# Example usage:
file_path = "data.txt"
ins_list = ['1.png',
'2.png',
'3.png',
'4.png',
'5.png']
async def instruction_message(call: types.CallbackQuery):
logger.info(f"{call.from_user.id} - @{call.from_user.username} : инструкция")
add_rec(call.from_user.id, 0)
await call.message.delete()
await bot.send_photo(call.from_user.id, FSInputFile('pictures/1.png', 'rb'), reply_markup=get_event_keyboard(0))
async def update_instruction(message: types.Message, new_value: int):
photo = FSInputFile(f'pictures/{new_value + 1}.png')
await message.edit_media(types.InputMediaPhoto(media=photo), reply_markup=get_event_keyboard(new_value))
async def callbacks_instruction(callback: types.CallbackQuery):
user_value = int(get_rec(callback.from_user.id))
action = callback.data.split("_")[1]
if action == "incr":
if len(ins_list) > user_value + 1:
add_rec(callback.from_user.id, user_value + 1)
await update_instruction(callback.message, user_value + 1)
elif action == "decr":
if user_value - 1 >= 0:
add_rec(callback.from_user.id, user_value - 1)
await update_instruction(callback.message, user_value - 1)
#print("-1")
await callback.answer()

View File

@ -0,0 +1,27 @@
from aiogram import Router
from aiogram.filters import Command
from aiogram import F
from handlers.start_handler import (command_start,
get_main_menu_answer,
get_main_menu_after_picture)
from handlers.instruction import (instruction_message,
callbacks_instruction)
def register_all_handlers(router: Router):
handle_register_start_message(router)
handle_instruction_message(router)
def handle_register_start_message(router: Router):
router.message.register(command_start, Command(commands=["start"]))
router.callback_query.register(get_main_menu_after_picture, F.data.startswith('main_menu_delete'))
router.callback_query.register(get_main_menu_answer, F.data.startswith('main_menu'))
router.callback_query.register(instruction_message, F.data.startswith("instruction_inline"))
def handle_instruction_message(router: Router):
router.callback_query.register(callbacks_instruction, F.data.startswith("num_"))

View File

@ -0,0 +1,73 @@
import asyncio
from aiogram import Bot, Dispatcher, types
import re
import os
import time
import shutil
import random
from create_bot import bot, request_url, important_message, url, token, bucket_name, username, password, endpoint_url
from req import check_register
import urllib.request
from messages import get_main_menu_message
from aiogram.fsm.context import FSMContext
from aiogram.fsm.state import State, StatesGroup
from aiogram.enums import ParseMode
from aiogram.types import ReplyKeyboardMarkup, KeyboardButton, ReplyKeyboardRemove, InlineKeyboardMarkup, InlineKeyboardButton, WebAppInfo
from loguru import logger
import boto3
from botocore.config import Config
def get_answer_keyboard():
button1 = InlineKeyboardButton(text='Главное меню', callback_data='main_menu')
kb = [[button1]]
keyboard = InlineKeyboardMarkup(inline_keyboard=kb)
return keyboard
def get_main_keyboard_inline(is_admin=False, ref_code=None):
button1 = InlineKeyboardButton(text='👾 Кликер', web_app=WebAppInfo(url=f'{url}?referred_by={ref_code}'))
button2 = InlineKeyboardButton(text=' Инструкция', callback_data='instruction_inline')
button3 = InlineKeyboardButton(text='🔥 Кто мы?', web_app=WebAppInfo(url='https://test.com'))
button4 = InlineKeyboardButton(text='ТЕСТ', callback_data='test_message')
kb = [[button1], [button2], [button3]]
if is_admin:
kb.append([button4])
keyboard = InlineKeyboardMarkup(inline_keyboard=kb)
return keyboard
def gen_ok_keyboard(number):
kb = [[InlineKeyboardButton(text='Подтвердить ✅', callback_data=f'approve_{number}'), InlineKeyboardButton(text='Изменить 🔄', callback_data=f'edit_{number}')]]
keyboard = InlineKeyboardMarkup(inline_keyboard=kb)
return keyboard
async def get_main_menu_answer(call: types.CallbackQuery):
logger.info(f"{call.from_user.id} - @{call.from_user.username} : главное меню через инлайн кнопку")
await call.message.edit_text(get_main_menu_message(), reply_markup=get_main_keyboard_inline(), parse_mode=ParseMode.MARKDOWN)
async def get_main_menu_after_picture(call: types.CallbackQuery):
logger.info(f"{call.from_user.id} - @{call.from_user.username} : главное меню через инлайн кнопку после картинки")
await call.message.delete()
await bot.send_message(call.from_user.id, get_main_menu_message(), reply_markup=get_main_keyboard_inline(), parse_mode=ParseMode.MARKDOWN)
async def command_start(message : types.Message):
ref_code = ''
if message.text[7:].startswith('user_'):
ref_code = message.text[12:]
if not check_register(message.from_user.id):
logger.info(f"{message.from_user.id} - @{message.from_user.username} : команда /start и не зарегистрирован")
await bot.send_message(message.from_user.id, '👋', reply_markup=ReplyKeyboardRemove())
# await asyncio.sleep(3)
await bot.send_message(message.from_user.id, '👑 Я - KYC Кликер бот! Зарабатывай баллы кликами, поднимайся в рейтинге и получай бонусы. Развивайся быстрее с нашей специальной системой для новичков!', reply_markup=ReplyKeyboardRemove())
# await asyncio.sleep(3)
await bot.send_message(message.from_user.id, '🎁 Используй баллы в аукционе за ценные призы! Победителей много, приглашаем в увлекательную битву кликов!', reply_markup=ReplyKeyboardRemove())
# await asyncio.sleep(3)
await bot.send_message(message.from_user.id, '👯 Участвуй в реферальной программе, чтобы получать % с кликов друзей и зарабатывать больше баллов для аукциона. ', reply_markup=ReplyKeyboardRemove())
# await asyncio.sleep(3)
await bot.send_message(message.from_user.id, '🍀 Удачи в битве!', reply_markup=ReplyKeyboardRemove())
# await asyncio.sleep(3)
else:
logger.info(f"{message.from_user.id} - @{message.from_user.username} : команда /start")
await bot.send_message(message.from_user.id, get_main_menu_message(), reply_markup=get_main_keyboard_inline(ref_code=ref_code), parse_mode=ParseMode.MARKDOWN)

21
bot/log.ini Normal file
View File

@ -0,0 +1,21 @@
[loggers]
keys=root
[handlers]
keys=logfile
[formatters]
keys=logfileformatter
[logger_root]
level=INFO
handlers=logfile
[formatter_logfileformatter]
format=[%(asctime)s.%(msecs)03d] %(levelname)s [%(thread)d] - %(message)s
[handler_logfile]
class=handlers.RotatingFileHandler
level=INFO
args=('logfile.log','a')
formatter=logfileformatter

8
bot/logs.log Normal file
View File

@ -0,0 +1,8 @@
2024-10-27T23:59:11.744491+0300 | main : main | INFO | Starting bot
2024-10-27T23:59:12.269505+0300 | start_handler : command_start | INFO | 7080735869 - @danya_danya23 : команда /start и не зарегистрирован
2024-10-28T00:00:35.215099+0300 | start_handler : command_start | INFO | 193428034 - @s1lur : команда /start и не зарегистрирован
2024-10-28T00:00:35.270428+0300 | start_handler : command_start | INFO | 402449803 - @danyadjan : команда /start и не зарегистрирован
2024-10-28T00:01:50.305932+0300 | main : main | INFO | Starting bot
2024-10-28T00:01:50.735100+0300 | start_handler : command_start | INFO | 402449803 - @danyadjan : команда /start и не зарегистрирован
2024-10-28T00:02:04.042345+0300 | main : main | INFO | Starting bot
2024-10-28T00:02:06.132110+0300 | start_handler : command_start | INFO | 402449803 - @danyadjan : команда /start и не зарегистрирован

15
bot/main.py Normal file
View File

@ -0,0 +1,15 @@
import asyncio
from loguru import logger
from wrapper import run_bot
def main():
try:
logger.info("Starting bot")
asyncio.run(run_bot())
except KeyboardInterrupt:
logger.info("Interrupted by user, shutting down")
return
if __name__ == "__main__":
main()

52
bot/main_api.py Normal file
View File

@ -0,0 +1,52 @@
import os
import secrets
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from create_bot import bot
from config import on_startup, on_shutdown
from routes import bot_api_router
from back_send import send_message_router
def init_app():
app = FastAPI(
title='Clicker Bot',
description='',
version='1',
)
@app.on_event('startup')
async def startup():
await on_startup()
@app.on_event('shutdown')
async def shutdown():
await on_shutdown()
app.include_router(
bot_api_router,
prefix=''
)
app.include_router(
send_message_router,
prefix=''
)
origins = [
'bot:7313',
'localhost:7313',
]
app.add_middleware(
CORSMiddleware,
allow_origins=origins,
allow_credentials=True,
allow_methods=['*'],
allow_headers=['*']
)
return app
app = init_app()

11
bot/memcached_def.py Normal file
View File

@ -0,0 +1,11 @@
import os
from pymemcache.client import base
client = base.Client((os.getenv('mem_host', 'localhost'), os.getenv('mem_port', 11211)))
def add_rec(key, value):
client.set(str(key), value)
def get_rec(key):
value = client.get(str(key))
return (int(value))

6
bot/messages.py Normal file
View File

@ -0,0 +1,6 @@
def get_main_menu_message():
msg = '🏠*ГЛАВНОЕ МЕНЮ*'
msg1 = '👾 *Кликер* - Играй и соревнуйся с другими участниками!'
msg2 = ' *Инструкция* - Читай, чтобы правильно использовать кликер!'
msg3 = '🔥 *Кто мы?* - Узнай больше о нас и нашей компании!'
return f'{msg}\n\n{msg1}\n{msg2}\n{msg3}'

BIN
bot/pictures/.DS_Store vendored Normal file

Binary file not shown.

BIN
bot/pictures/1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 614 KiB

BIN
bot/pictures/2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 666 KiB

BIN
bot/pictures/3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 561 KiB

BIN
bot/pictures/4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 642 KiB

BIN
bot/pictures/5.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 571 KiB

14
bot/req.py Normal file
View File

@ -0,0 +1,14 @@
import json
import re
import requests
from loguru import logger
from create_bot import request_url, api_token
from operator import itemgetter
from loguru import logger
def check_register(tg_id):
return False
def check_admin(tg_id):
return 0

17
bot/routes.py Normal file
View File

@ -0,0 +1,17 @@
from fastapi import APIRouter
from aiogram import types, Dispatcher, Bot
from create_bot import bot, token
from config import dp
bot_api_router = APIRouter(
prefix=f'/bot/wh',
)
@bot_api_router.post(f'/{token}', include_in_schema=False)
async def bot_webhook(update: dict):
telegram_update = types.Update(**update)
Dispatcher.set_current(dp)
Bot.set_current(bot)
await dp.process_update(telegram_update)

7
bot/scripts/gunicorn.sh Normal file
View File

@ -0,0 +1,7 @@
#!/usr/bin/env bash
set -o errexit
set -o pipefail
set -o nounset
gunicorn main_api:app -w 17 -b 0.0.0.0:7313 -k uvicorn.workers.UvicornWorker --timeout 600

8
bot/scripts/start.sh Normal file
View File

@ -0,0 +1,8 @@
#!/usr/bin/env bash
set -o errexit
set -o pipefail
set -o nounset
set -o xtrace
uvicorn main_api:app --host 0.0.0.0 --port 7313 --log-config /app/log.ini

23
bot/wrapper.py Normal file
View File

@ -0,0 +1,23 @@
from handlers.register_handlers import register_all_handlers
from create_bot import bot
from aiogram import Bot, Dispatcher
from aiogram.fsm.storage.memory import MemoryStorage
from loguru import logger
from aiogram import Router
logger.add("logs.log", format = "{time} | {module} : {function} | {level} | {message}", level = "INFO", rotation = "1 week", compression = "zip")#, serialize = True)
async def run_bot():
storage = MemoryStorage()
dp = Dispatcher(storage=storage)
# Create a router to register handlers
router = Router()
# Register all handlers
register_all_handlers(router)
# Mount the router into the dispatcher
dp.include_router(router)
await dp.start_polling(bot)