mirror of
https://github.com/djimboy/djimbo_template_aio3.git
synced 2026-07-25 01:34:30 +00:00
Update
This commit is contained in:
+189
@@ -0,0 +1,189 @@
|
|||||||
|
# Byte-compiled / optimized / DLL files
|
||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
*$py.class
|
||||||
|
|
||||||
|
# C extensions
|
||||||
|
*.so
|
||||||
|
|
||||||
|
# Distribution / packaging
|
||||||
|
.Python
|
||||||
|
env/
|
||||||
|
build/
|
||||||
|
develop-eggs/
|
||||||
|
dist/
|
||||||
|
downloads/
|
||||||
|
eggs/
|
||||||
|
.eggs/
|
||||||
|
lib/
|
||||||
|
lib64/
|
||||||
|
parts/
|
||||||
|
sdist/
|
||||||
|
var/
|
||||||
|
*.egg-info/
|
||||||
|
.installed.cfg
|
||||||
|
*.egg
|
||||||
|
|
||||||
|
# PyInstaller
|
||||||
|
# Usually these files are written by a python script from a template
|
||||||
|
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||||
|
*.manifest
|
||||||
|
*.spec
|
||||||
|
|
||||||
|
# Installer logs
|
||||||
|
pip-log.txt
|
||||||
|
pip-delete-this-directory.txt
|
||||||
|
|
||||||
|
# Unit test / coverage reports
|
||||||
|
htmlcov/
|
||||||
|
.tox/
|
||||||
|
.coverage
|
||||||
|
.coverage.*
|
||||||
|
.cache
|
||||||
|
nosetests.xml
|
||||||
|
coverage.xml
|
||||||
|
*,cover
|
||||||
|
.hypothesis/
|
||||||
|
|
||||||
|
# Translations
|
||||||
|
*.mo
|
||||||
|
*.pot
|
||||||
|
|
||||||
|
# Django stuff:
|
||||||
|
*.log
|
||||||
|
local_settings.py
|
||||||
|
|
||||||
|
# Flask stuff:
|
||||||
|
instance/
|
||||||
|
.webassets-cache
|
||||||
|
|
||||||
|
# Scrapy stuff:
|
||||||
|
.scrapy
|
||||||
|
|
||||||
|
# Sphinx documentation
|
||||||
|
docs/_build/
|
||||||
|
|
||||||
|
# PyBuilder
|
||||||
|
target/
|
||||||
|
|
||||||
|
# IPython Notebook
|
||||||
|
.ipynb_checkpoints
|
||||||
|
|
||||||
|
# pyenv
|
||||||
|
.python-version
|
||||||
|
|
||||||
|
# celery beat schedule file
|
||||||
|
celerybeat-schedule
|
||||||
|
|
||||||
|
# dotenv
|
||||||
|
.env
|
||||||
|
|
||||||
|
# virtualenv
|
||||||
|
venv/
|
||||||
|
ENV/
|
||||||
|
|
||||||
|
# Spyder project settings
|
||||||
|
.spyderproject
|
||||||
|
|
||||||
|
# Rope project settings
|
||||||
|
.ropeproject
|
||||||
|
### VirtualEnv template
|
||||||
|
# Virtualenv
|
||||||
|
# http://iamzed.com/2009/05/07/a-primer-on-virtualenv/
|
||||||
|
[Bb]in
|
||||||
|
[Ii]nclude
|
||||||
|
[Ll]ib
|
||||||
|
[Ll]ib64
|
||||||
|
[Ll]ocal
|
||||||
|
[Ss]cripts
|
||||||
|
pyvenv.cfg
|
||||||
|
.venv
|
||||||
|
pip-selfcheck.json
|
||||||
|
|
||||||
|
### JetBrains template
|
||||||
|
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
|
||||||
|
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
||||||
|
|
||||||
|
# User-specific stuff
|
||||||
|
.idea/**/workspace.xml
|
||||||
|
.idea/**/tasks.xml
|
||||||
|
.idea/**/usage.statistics.xml
|
||||||
|
.idea/**/dictionaries
|
||||||
|
.idea/**/shelf
|
||||||
|
|
||||||
|
# AWS User-specific
|
||||||
|
.idea/**/aws.xml
|
||||||
|
|
||||||
|
# Generated files
|
||||||
|
.idea/**/contentModel.xml
|
||||||
|
|
||||||
|
# Sensitive or high-churn files
|
||||||
|
.idea/**/dataSources/
|
||||||
|
.idea/**/dataSources.ids
|
||||||
|
.idea/**/dataSources.local.xml
|
||||||
|
.idea/**/sqlDataSources.xml
|
||||||
|
.idea/**/dynamic.xml
|
||||||
|
.idea/**/uiDesigner.xml
|
||||||
|
.idea/**/dbnavigator.xml
|
||||||
|
|
||||||
|
# Gradle
|
||||||
|
.idea/**/gradle.xml
|
||||||
|
.idea/**/libraries
|
||||||
|
|
||||||
|
# Gradle and Maven with auto-import
|
||||||
|
# When using Gradle or Maven with auto-import, you should exclude module files,
|
||||||
|
# since they will be recreated, and may cause churn. Uncomment if using
|
||||||
|
auto-import.
|
||||||
|
.idea/artifacts
|
||||||
|
.idea/compiler.xml
|
||||||
|
.idea/jarRepositories.xml
|
||||||
|
.idea/modules.xml
|
||||||
|
.idea/*.iml
|
||||||
|
.idea/modules
|
||||||
|
*.iml
|
||||||
|
*.ipr
|
||||||
|
|
||||||
|
# CMake
|
||||||
|
cmake-build-*/
|
||||||
|
|
||||||
|
# Mongo Explorer plugin
|
||||||
|
.idea/**/mongoSettings.xml
|
||||||
|
|
||||||
|
# File-based project format
|
||||||
|
*.iws
|
||||||
|
|
||||||
|
# IntelliJ
|
||||||
|
out/
|
||||||
|
|
||||||
|
# mpeltonen/sbt-idea plugin
|
||||||
|
.idea_modules/
|
||||||
|
|
||||||
|
# JIRA plugin
|
||||||
|
atlassian-ide-plugin.xml
|
||||||
|
|
||||||
|
# Cursive Clojure plugin
|
||||||
|
.idea/replstate.xml
|
||||||
|
|
||||||
|
# SonarLint plugin
|
||||||
|
.idea/sonarlint/
|
||||||
|
|
||||||
|
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||||
|
com_crashlytics_export_strings.xml
|
||||||
|
crashlytics.properties
|
||||||
|
crashlytics-build.properties
|
||||||
|
fabric.properties
|
||||||
|
|
||||||
|
# Editor-based Rest Client
|
||||||
|
.idea/httpRequests
|
||||||
|
|
||||||
|
# Android studio 3.1+ serialized cache file
|
||||||
|
.idea/caches/build_file_checksums.ser
|
||||||
|
|
||||||
|
# idea folder, uncomment if you don't need it
|
||||||
|
.idea
|
||||||
|
|
||||||
|
# Users exceptions
|
||||||
|
/other/
|
||||||
|
/tgbot/data/database.db
|
||||||
|
/tgbot/data/logs.log
|
||||||
|
settings.ini
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
# - *- coding: utf- 8 - *-
|
||||||
|
import asyncio
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
import colorama
|
||||||
|
from aiogram import Bot, Dispatcher
|
||||||
|
|
||||||
|
from tgbot.config import BOT_TOKEN, scheduler, get_admins
|
||||||
|
from tgbot.middlewares import register_all_middlwares
|
||||||
|
from tgbot.routers import register_all_routers
|
||||||
|
from tgbot.services.api_session import RequestsSession
|
||||||
|
from tgbot.services.api_sqlite import create_dbx
|
||||||
|
from tgbot.utils.misc.bot_commands import set_commands
|
||||||
|
from tgbot.utils.misc.bot_logging import bot_logger
|
||||||
|
from tgbot.utils.misc_functions import autobackup, startup_notify
|
||||||
|
|
||||||
|
colorama.init()
|
||||||
|
|
||||||
|
|
||||||
|
# Запуск шедулеров
|
||||||
|
async def scheduler_start(bot):
|
||||||
|
scheduler.add_job(autobackup, "cron", hour=00, args=(bot,)) # Автобэкап в 12:00
|
||||||
|
scheduler.add_job(autobackup, "cron", hour=12, args=(bot,)) # Автобэкап в 00:00
|
||||||
|
|
||||||
|
|
||||||
|
# Запуск бота и функций
|
||||||
|
async def main():
|
||||||
|
scheduler.start() # Запуск Шедулера
|
||||||
|
dp = Dispatcher() # Создание Диспетчера
|
||||||
|
rSession = RequestsSession() # Асинхронные Запросы
|
||||||
|
bot = Bot(token=BOT_TOKEN, parse_mode="HTML") # Образ Бота
|
||||||
|
|
||||||
|
register_all_middlwares(dp) # Регистрация всех мидлварей
|
||||||
|
register_all_routers(dp) # Регистрация всех роутеров
|
||||||
|
|
||||||
|
try:
|
||||||
|
await set_commands(bot)
|
||||||
|
await startup_notify(bot)
|
||||||
|
await scheduler_start(bot)
|
||||||
|
|
||||||
|
bot_logger.warning("Bot was started")
|
||||||
|
print(colorama.Fore.LIGHTYELLOW_EX + "~~~~~ Bot was started ~~~~~")
|
||||||
|
print(colorama.Fore.LIGHTBLUE_EX + "~~~~~ TG developer: @djimbox ~~~~~")
|
||||||
|
print(colorama.Fore.RESET)
|
||||||
|
|
||||||
|
if len(get_admins()) == 0: print("***** ENTER ADMIN ID IN settings.ini *****")
|
||||||
|
|
||||||
|
await bot.delete_webhook()
|
||||||
|
await bot.get_updates(offset=-1)
|
||||||
|
await dp.start_polling(bot, allowed_updates=dp.resolve_used_update_types(), rSession=rSession)
|
||||||
|
finally:
|
||||||
|
await rSession.close()
|
||||||
|
await bot.session.close()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
create_dbx()
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Исправление "RuntimeError: Event loop is closed" для Windows
|
||||||
|
# if sys.version_info[0] == 3 and sys.version_info[1] >= 8 and sys.platform.startswith("win"):
|
||||||
|
# asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
|
||||||
|
|
||||||
|
asyncio.run(main())
|
||||||
|
except (KeyboardInterrupt, SystemExit):
|
||||||
|
bot_logger.warning("Bot was stopped")
|
||||||
|
finally:
|
||||||
|
if sys.platform.startswith("win"):
|
||||||
|
os.system("cls")
|
||||||
|
else:
|
||||||
|
os.system("clear")
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
colorlog
|
||||||
|
aiogram>=3.0.0b2
|
||||||
|
aiohttp
|
||||||
|
typing
|
||||||
|
APScheduler==3.8.0
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
# - *- coding: utf- 8 - *-
|
||||||
|
import configparser
|
||||||
|
|
||||||
|
from apscheduler.schedulers.asyncio import AsyncIOScheduler
|
||||||
|
|
||||||
|
from tgbot.utils.const_functions import clear_list
|
||||||
|
|
||||||
|
scheduler = AsyncIOScheduler()
|
||||||
|
|
||||||
|
read_config = configparser.ConfigParser()
|
||||||
|
read_config.read("settings.ini")
|
||||||
|
|
||||||
|
BOT_TOKEN = read_config["settings"]["token"].strip()
|
||||||
|
PATH_DATABASE = "tgbot/data/database.db" # Путь к БД
|
||||||
|
PATH_LOGS = "tgbot/data/logs.log" # Путь к Логам
|
||||||
|
|
||||||
|
|
||||||
|
# Получение администраторов бота
|
||||||
|
def get_admins():
|
||||||
|
read_admins = configparser.ConfigParser()
|
||||||
|
read_admins.read("settings.ini")
|
||||||
|
|
||||||
|
admins = read_admins["settings"]["admin_id"].strip()
|
||||||
|
admins = admins.replace(" ", "")
|
||||||
|
|
||||||
|
if "," in admins:
|
||||||
|
admins = admins.split(",")
|
||||||
|
else:
|
||||||
|
if len(admins) >= 1:
|
||||||
|
admins = [admins]
|
||||||
|
else:
|
||||||
|
admins = []
|
||||||
|
|
||||||
|
admins = list(map(int, clear_list(admins)))
|
||||||
|
|
||||||
|
return admins
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
# - *- coding: utf- 8 - *-
|
||||||
|
import configparser
|
||||||
|
|
||||||
|
from apscheduler.schedulers.asyncio import AsyncIOScheduler
|
||||||
|
|
||||||
|
scheduler = AsyncIOScheduler()
|
||||||
|
|
||||||
|
read_config = configparser.ConfigParser()
|
||||||
|
read_config.read("settings.ini")
|
||||||
|
|
||||||
|
BOT_TOKEN = read_config['settings']['token'].strip() # Токен бота
|
||||||
|
PATH_DATABASE = "tgbot/data/database.db" # Путь к БД
|
||||||
|
PATH_LOGS = "tgbot/data/logs.log" # Путь к Логам
|
||||||
|
|
||||||
|
|
||||||
|
# Получение администраторов бота
|
||||||
|
def get_admins():
|
||||||
|
read_admins = configparser.ConfigParser()
|
||||||
|
read_admins.read('settings.ini')
|
||||||
|
admins = read_admins['settings']['admin_id'].strip()
|
||||||
|
admins = admins.replace(' ', '')
|
||||||
|
|
||||||
|
if ',' in admins:
|
||||||
|
admins = admins.split(',')
|
||||||
|
else:
|
||||||
|
if len(admins) >= 1:
|
||||||
|
admins = [admins]
|
||||||
|
else:
|
||||||
|
admins = []
|
||||||
|
|
||||||
|
while "" in admins: admins.remove("")
|
||||||
|
while " " in admins: admins.remove(" ")
|
||||||
|
while "," in admins: admins.remove(",")
|
||||||
|
while "\r" in admins: admins.remove("\r")
|
||||||
|
|
||||||
|
admins = list(map(int, admins))
|
||||||
|
|
||||||
|
return admins
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
# - *- coding: utf- 8 - *-
|
||||||
|
from aiogram.utils.keyboard import InlineKeyboardBuilder
|
||||||
|
|
||||||
|
from tgbot.data.config import get_admins
|
||||||
|
from tgbot.utils.const_functions import ikb
|
||||||
|
|
||||||
|
|
||||||
|
# Кнопки инлайн меню
|
||||||
|
def menu_finl(user_id):
|
||||||
|
keyboard = InlineKeyboardBuilder(
|
||||||
|
).row(
|
||||||
|
ikb("User 1", data="..."),
|
||||||
|
ikb("User 2", data="...")
|
||||||
|
)
|
||||||
|
|
||||||
|
if user_id in get_admins():
|
||||||
|
keyboard.row(
|
||||||
|
ikb("Admin 1", data="..."),
|
||||||
|
ikb("Admin 2", data="...")
|
||||||
|
)
|
||||||
|
|
||||||
|
return keyboard.as_markup()
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
# - *- coding: utf- 8 - *-
|
||||||
|
from aiogram.utils.keyboard import InlineKeyboardBuilder
|
||||||
|
|
||||||
|
from tgbot.utils.const_functions import ikb
|
||||||
|
|
||||||
|
# Тестовые админ инлайн кнопки
|
||||||
|
admin_inl = InlineKeyboardBuilder(
|
||||||
|
).row(
|
||||||
|
ikb("Admin Inline 1", data="..."),
|
||||||
|
ikb("Admin Inline 2", data="..."),
|
||||||
|
).row(
|
||||||
|
ikb("Admin Inline 3", data="..."),
|
||||||
|
).as_markup()
|
||||||
|
|
||||||
|
# Тестовые юзер инлайн кнопки
|
||||||
|
user_inl = InlineKeyboardBuilder(
|
||||||
|
).row(
|
||||||
|
ikb("User Inline 1", data="..."),
|
||||||
|
ikb("User Inline 2", data="..."),
|
||||||
|
).row(
|
||||||
|
ikb("User Inline 3", data="..."),
|
||||||
|
).as_markup()
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
# - *- coding: utf- 8 - *-
|
||||||
|
from aiogram.utils.keyboard import ReplyKeyboardBuilder
|
||||||
|
|
||||||
|
from tgbot.data.config import get_admins
|
||||||
|
from tgbot.utils.const_functions import rkb
|
||||||
|
|
||||||
|
|
||||||
|
# Кнопки главного меню
|
||||||
|
def menu_frep(user_id):
|
||||||
|
keyboard = ReplyKeyboardBuilder(
|
||||||
|
).row(
|
||||||
|
rkb("User Inline"), rkb("User Reply"),
|
||||||
|
)
|
||||||
|
|
||||||
|
if user_id in get_admins():
|
||||||
|
keyboard.row(
|
||||||
|
rkb("Admin Inline"), rkb("Admin Reply"),
|
||||||
|
)
|
||||||
|
|
||||||
|
return keyboard.as_markup(resize_keyboard=True)
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
# - *- coding: utf- 8 - *-
|
||||||
|
from aiogram.utils.keyboard import ReplyKeyboardBuilder
|
||||||
|
|
||||||
|
from tgbot.utils.const_functions import rkb
|
||||||
|
|
||||||
|
# Тестовые админ реплай кнопки
|
||||||
|
admin_rep = ReplyKeyboardBuilder(
|
||||||
|
).row(
|
||||||
|
rkb("Admin Reply 1"),
|
||||||
|
rkb("Admin Reply 2"),
|
||||||
|
).row(
|
||||||
|
rkb("⬅ Главное меню"),
|
||||||
|
).as_markup(resize_keyboard=True)
|
||||||
|
|
||||||
|
# Тестовые юзер реплай кнопки
|
||||||
|
user_rep = ReplyKeyboardBuilder(
|
||||||
|
).row(
|
||||||
|
rkb("User Reply 1"),
|
||||||
|
rkb("User Reply 2"),
|
||||||
|
).row(
|
||||||
|
rkb("⬅ Главное меню"),
|
||||||
|
).as_markup(resize_keyboard=True)
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
# - *- coding: utf- 8 - *-
|
||||||
|
from aiogram import Dispatcher
|
||||||
|
|
||||||
|
from tgbot.middlewares.exists_user import ExistsUserMiddleware
|
||||||
|
from tgbot.middlewares.throttling import ThrottlingMiddleware
|
||||||
|
|
||||||
|
|
||||||
|
def register_all_middlwares(dp: Dispatcher):
|
||||||
|
dp.callback_query.outer_middleware(ExistsUserMiddleware())
|
||||||
|
dp.message.outer_middleware(ExistsUserMiddleware())
|
||||||
|
|
||||||
|
dp.message.middleware(ThrottlingMiddleware())
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
# - *- coding: utf- 8 - *-
|
||||||
|
from aiogram import BaseMiddleware
|
||||||
|
|
||||||
|
from tgbot.services.api_sqlite import get_userx, add_userx, update_userx
|
||||||
|
from tgbot.utils.const_functions import clear_html
|
||||||
|
|
||||||
|
|
||||||
|
# Проверка юзера в БД и его добавление
|
||||||
|
class ExistsUserMiddleware(BaseMiddleware):
|
||||||
|
async def __call__(self, handler, event, data):
|
||||||
|
this_user = data.get("event_from_user")
|
||||||
|
|
||||||
|
if not this_user.is_bot:
|
||||||
|
get_user = get_userx(user_id=this_user.id)
|
||||||
|
|
||||||
|
user_id = this_user.id
|
||||||
|
user_login = this_user.username
|
||||||
|
user_name = clear_html(this_user.first_name)
|
||||||
|
user_fullname = clear_html(this_user.first_name)
|
||||||
|
user_surname = clear_html(this_user.last_name)
|
||||||
|
user_language = this_user.language_code
|
||||||
|
|
||||||
|
if user_language != "ru": user_language = "en"
|
||||||
|
if user_login is None: user_login = ""
|
||||||
|
if user_name is None: user_name = ""
|
||||||
|
if user_fullname is None: user_fullname = ""
|
||||||
|
if user_surname is None: user_surname = ""
|
||||||
|
|
||||||
|
if len(user_surname) >= 1: user_fullname += f" {user_surname}"
|
||||||
|
|
||||||
|
if get_user is None:
|
||||||
|
add_userx(user_id, user_login.lower(), user_name, user_surname, user_fullname)
|
||||||
|
else:
|
||||||
|
if user_name != get_user['user_name']:
|
||||||
|
update_userx(get_user['user_id'], user_name=user_name)
|
||||||
|
|
||||||
|
if user_surname != get_user['user_surname']:
|
||||||
|
update_userx(get_user['user_id'], user_surname=user_surname)
|
||||||
|
|
||||||
|
if user_fullname != get_user['user_fullname']:
|
||||||
|
update_userx(get_user['user_id'], user_fullname=user_fullname)
|
||||||
|
|
||||||
|
if user_login.lower() != get_user['user_login']:
|
||||||
|
update_userx(get_user['user_id'], user_login=user_login.lower())
|
||||||
|
|
||||||
|
data['my_user'] = get_userx(user_id=user_id)
|
||||||
|
|
||||||
|
return await handler(event, data)
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
# - *- coding: utf- 8 - *-
|
||||||
|
import time
|
||||||
|
from typing import Any, Awaitable, Callable, Dict
|
||||||
|
|
||||||
|
from aiogram import BaseMiddleware
|
||||||
|
from aiogram.dispatcher.event.handler import HandlerObject
|
||||||
|
from aiogram.types import Message
|
||||||
|
|
||||||
|
from tgbot.services.api_sqlite import get_userx
|
||||||
|
|
||||||
|
|
||||||
|
# Антиспам
|
||||||
|
class ThrottlingMiddleware(BaseMiddleware):
|
||||||
|
def __init__(self, default_rate: int = 0.6) -> None:
|
||||||
|
self.default_rate = default_rate
|
||||||
|
self.now_rate = default_rate
|
||||||
|
|
||||||
|
self.last_throttled = int(time.time())
|
||||||
|
self.count_throttled = 0
|
||||||
|
|
||||||
|
async def __call__(self, handler: Callable[[Message, Dict[str, Any]], Awaitable[Any]], event: Message, data):
|
||||||
|
real_handler: HandlerObject = data['handler']
|
||||||
|
skip_pass = True
|
||||||
|
|
||||||
|
this_user = data.get("event_from_user")
|
||||||
|
if not this_user.is_bot:
|
||||||
|
data['get_user'] = get_userx(user_id=this_user.id)
|
||||||
|
|
||||||
|
if real_handler.flags.get("skip_pass") is not None:
|
||||||
|
skip_pass = real_handler.flags.get("skip_pass")
|
||||||
|
|
||||||
|
if skip_pass:
|
||||||
|
if int(time.time()) - self.last_throttled >= self.now_rate:
|
||||||
|
self.last_throttled = int(time.time())
|
||||||
|
self.now_rate = self.default_rate
|
||||||
|
self.count_throttled = 0
|
||||||
|
|
||||||
|
return await handler(event, data)
|
||||||
|
else:
|
||||||
|
if self.count_throttled == 0:
|
||||||
|
self.count_throttled += 1
|
||||||
|
self.now_rate = self.default_rate * 2
|
||||||
|
|
||||||
|
return await handler(event, data)
|
||||||
|
elif self.count_throttled == 1:
|
||||||
|
self.count_throttled += 1
|
||||||
|
self.now_rate = self.default_rate * 2
|
||||||
|
|
||||||
|
await event.reply("<b>❗ Пожалуйста, не спамьте.</b>")
|
||||||
|
else:
|
||||||
|
self.now_rate = 3
|
||||||
|
|
||||||
|
if self.count_throttled == 2:
|
||||||
|
self.count_throttled = 3
|
||||||
|
await event.reply("<b>❗ Бот не будет отвечать до прекращения спама.</b>")
|
||||||
|
|
||||||
|
self.last_throttled = int(time.time())
|
||||||
|
else:
|
||||||
|
return await handler(event, data)
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
# - *- coding: utf- 8 - *-
|
||||||
|
from aiogram import Dispatcher, F
|
||||||
|
|
||||||
|
from tgbot.routers import main_errors, main_missed, main_start
|
||||||
|
from tgbot.routers.admin import admin_menu
|
||||||
|
from tgbot.routers.user import user_menu
|
||||||
|
from tgbot.utils.misc.bot_filters import IsAdmin
|
||||||
|
|
||||||
|
|
||||||
|
# Регистрация роутеров
|
||||||
|
def register_all_routers(dp: Dispatcher):
|
||||||
|
# Подключение фильтров
|
||||||
|
main_errors.router.message.filter(F.chat.type == "private")
|
||||||
|
main_start.router.message.filter(F.chat.type == "private")
|
||||||
|
main_missed.router.message.filter(F.chat.type == "private")
|
||||||
|
|
||||||
|
user_menu.router.message.filter(F.chat.type == "private")
|
||||||
|
|
||||||
|
admin_menu.router.message.filter(F.chat.type == "private", IsAdmin())
|
||||||
|
|
||||||
|
# Инициализация обязательных роутеров
|
||||||
|
dp.include_router(main_errors.router)
|
||||||
|
dp.include_router(main_start.router)
|
||||||
|
|
||||||
|
# Подключение хендлеров (юзеров и админов)
|
||||||
|
dp.include_router(user_menu.router) # Юзер хендлер
|
||||||
|
dp.include_router(admin_menu.router) # Админ хендлер
|
||||||
|
|
||||||
|
# Инициализация обязательных роутеров
|
||||||
|
dp.include_router(main_missed.router)
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
# - *- coding: utf- 8 - *-
|
||||||
|
from aiogram import Router, Bot
|
||||||
|
from aiogram.types import FSInputFile, Message
|
||||||
|
|
||||||
|
from tgbot.config import PATH_DATABASE, PATH_LOGS
|
||||||
|
from tgbot.data.config import PATH_DATABASE, PATH_LOGS
|
||||||
|
from tgbot.keyboards.inline_misc import admin_inl
|
||||||
|
from tgbot.keyboards.reply_misc import admin_rep
|
||||||
|
from tgbot.utils.const_functions import get_date
|
||||||
|
from tgbot.utils.misc.bot_models import FSM, RS
|
||||||
|
|
||||||
|
router = Router()
|
||||||
|
|
||||||
|
|
||||||
|
# Кнопка - Admin Inline
|
||||||
|
@router.message(text="Admin Inline")
|
||||||
|
async def admin_button_inline(message: Message, bot: Bot, state: FSM, rSession: RS, my_user):
|
||||||
|
await state.clear()
|
||||||
|
|
||||||
|
await message.answer("Click Button - Admin Inline", reply_markup=admin_inl)
|
||||||
|
|
||||||
|
|
||||||
|
# Кнопка - Admin Reply
|
||||||
|
@router.message(text="Admin Reply")
|
||||||
|
async def admin_button_reply(message: Message, bot: Bot, state: FSM, rSession: RS, my_user):
|
||||||
|
await state.clear()
|
||||||
|
|
||||||
|
await message.answer("Click Button - Admin Reply", reply_markup=admin_rep)
|
||||||
|
|
||||||
|
|
||||||
|
# Получение Базы Данных
|
||||||
|
@router.message(commands=['db', 'database'])
|
||||||
|
async def admin_database(message: Message, bot: Bot, state: FSM, rSession: RS, my_user):
|
||||||
|
await state.clear()
|
||||||
|
|
||||||
|
await message.answer_document(FSInputFile(PATH_DATABASE),
|
||||||
|
caption=f"<b>📦 BACKUP</b>\n"
|
||||||
|
f"<code>🕰 {get_date()}</code>")
|
||||||
|
|
||||||
|
|
||||||
|
# Получение логов
|
||||||
|
@router.message(commands=['log', 'logs'])
|
||||||
|
async def admin_log(message: Message, bot: Bot, state: FSM, rSession: RS, my_user):
|
||||||
|
await state.clear()
|
||||||
|
|
||||||
|
await message.answer_document(FSInputFile(PATH_LOGS), caption=f"<code>🕰 {get_date()}</code>")
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
# - *- coding: utf- 8 - *-
|
||||||
|
from aiogram import Router, Bot
|
||||||
|
from aiogram.exceptions import TelegramAPIError
|
||||||
|
from aiogram.types import Update
|
||||||
|
|
||||||
|
from tgbot.utils.misc.bot_logging import bot_logger
|
||||||
|
from tgbot.utils.misc_functions import send_admins
|
||||||
|
|
||||||
|
router = Router()
|
||||||
|
|
||||||
|
|
||||||
|
# Обработка ошибок
|
||||||
|
@router.errors()
|
||||||
|
async def processing_errors(update: Update, exception: TelegramAPIError, bot: Bot):
|
||||||
|
print(f"-Exception | {exception}")
|
||||||
|
await send_admins(bot, f"<b>❌ Ошибка\n\n"
|
||||||
|
f"<b>Exception: <code>{exception}</code>\n\n"
|
||||||
|
f"Update: <code>{update.dict()}</code></b>")
|
||||||
|
|
||||||
|
bot_logger.exception(
|
||||||
|
f"Exception: {exception}\n"
|
||||||
|
f"Update: {update.dict()}"
|
||||||
|
)
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
# - *- coding: utf- 8 - *-
|
||||||
|
from aiogram import types, Router
|
||||||
|
from aiogram.types import CallbackQuery
|
||||||
|
|
||||||
|
from tgbot.keyboards.reply_main import menu_frep
|
||||||
|
from tgbot.utils.misc.bot_models import FSM
|
||||||
|
|
||||||
|
router = Router()
|
||||||
|
|
||||||
|
|
||||||
|
# Колбэк с удалением сообщения
|
||||||
|
@router.callback_query(text="close_this")
|
||||||
|
async def processing_callback_remove(call: CallbackQuery, state: FSM):
|
||||||
|
await call.message.delete()
|
||||||
|
|
||||||
|
|
||||||
|
# Колбэк с обработкой кнопки
|
||||||
|
@router.callback_query(text="...")
|
||||||
|
async def processing_callback_answer(call: CallbackQuery, state: FSM):
|
||||||
|
await call.answer(cache_time=20)
|
||||||
|
|
||||||
|
|
||||||
|
# Колбэк с обработкой удаления сообщений потерявших стейт
|
||||||
|
@router.callback_query()
|
||||||
|
async def processing_callback_missed(call: CallbackQuery, state: FSM):
|
||||||
|
try:
|
||||||
|
await call.message.delete()
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
await call.message.answer("<b>❌ Данные не были найдены из-за перезапуска скрипта.\n"
|
||||||
|
"♻ Выполните действие заново.</b>",
|
||||||
|
reply_markup=menu_frep(call.from_user.id))
|
||||||
|
|
||||||
|
|
||||||
|
# Обработка всех неизвестных команд
|
||||||
|
@router.message()
|
||||||
|
async def processing_message_missed(message: types.Message, state: FSM):
|
||||||
|
await message.answer("♦ Неизвестная команда.\n"
|
||||||
|
"▶ Введите /start")
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
# - *- coding: utf- 8 - *-
|
||||||
|
from aiogram import Router, Bot
|
||||||
|
from aiogram.types import Message
|
||||||
|
|
||||||
|
from tgbot.keyboards.reply_main import menu_frep
|
||||||
|
from tgbot.utils.misc.bot_models import FSM, RS
|
||||||
|
|
||||||
|
router = Router()
|
||||||
|
|
||||||
|
|
||||||
|
# Открытие главного меню
|
||||||
|
@router.message(text_startswith=["⬅ Главное меню", "/start"])
|
||||||
|
async def main_start(message: Message, bot: Bot, state: FSM, rSession: RS, my_user):
|
||||||
|
await state.clear()
|
||||||
|
|
||||||
|
await message.answer("🔸 Бот готов к использованию.\n"
|
||||||
|
"🔸 Если не появились вспомогательные кнопки\n"
|
||||||
|
"▶ Введите /start",
|
||||||
|
reply_markup=menu_frep(message.from_user.id))
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
# - *- coding: utf- 8 - *-
|
||||||
|
from aiogram import Router, Bot
|
||||||
|
from aiogram.types import Message
|
||||||
|
|
||||||
|
from tgbot.keyboards.inline_main import menu_finl
|
||||||
|
from tgbot.keyboards.inline_misc import user_inl
|
||||||
|
from tgbot.keyboards.reply_misc import user_rep
|
||||||
|
from tgbot.utils.misc.bot_models import FSM, RS
|
||||||
|
|
||||||
|
router = Router()
|
||||||
|
|
||||||
|
|
||||||
|
# Кнопка - User Inline
|
||||||
|
@router.message(text="User Inline")
|
||||||
|
async def user_button_inline(message: Message, bot: Bot, state: FSM, rSession: RS, my_user):
|
||||||
|
await state.clear()
|
||||||
|
|
||||||
|
await message.answer("Click Button - User Inline", reply_markup=user_inl)
|
||||||
|
|
||||||
|
|
||||||
|
# Кнопка - User Reply
|
||||||
|
@router.message(text="User Reply")
|
||||||
|
async def user_button_reply(message: Message, bot: Bot, state: FSM, rSession: RS, my_user):
|
||||||
|
await state.clear()
|
||||||
|
|
||||||
|
await message.answer("Click Button - User Reply", reply_markup=user_rep)
|
||||||
|
|
||||||
|
|
||||||
|
# Команда - /inline
|
||||||
|
@router.message(commands="inline")
|
||||||
|
async def user_command_inline(message: Message, bot: Bot, state: FSM, rSession: RS, my_user):
|
||||||
|
await state.clear()
|
||||||
|
|
||||||
|
await message.answer("Click command - /inline", reply_markup=menu_finl(message.from_user.id))
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
# - *- coding: utf- 8 - *-
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
import aiohttp
|
||||||
|
|
||||||
|
|
||||||
|
# Асинхронная сессия для запросов
|
||||||
|
class RequestsSession:
|
||||||
|
def __init__(self) -> None:
|
||||||
|
self._session: Optional[aiohttp.ClientSession] = None
|
||||||
|
|
||||||
|
# Получение сессии
|
||||||
|
async def get_session(self) -> aiohttp.ClientSession:
|
||||||
|
if self._session is None:
|
||||||
|
new_session = aiohttp.ClientSession()
|
||||||
|
self._session = new_session
|
||||||
|
|
||||||
|
return self._session
|
||||||
|
|
||||||
|
# Закрытие сессии
|
||||||
|
async def close(self) -> None:
|
||||||
|
if self._session is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
await self._session.close()
|
||||||
@@ -0,0 +1,125 @@
|
|||||||
|
# - *- coding: utf- 8 - *-
|
||||||
|
import sqlite3
|
||||||
|
|
||||||
|
from tgbot.config import PATH_DATABASE
|
||||||
|
from tgbot.utils.const_functions import get_unix, get_date
|
||||||
|
|
||||||
|
|
||||||
|
# Преобразование БД словаря
|
||||||
|
def dict_factory(cursor, row):
|
||||||
|
this_dict = {}
|
||||||
|
|
||||||
|
for idx, col in enumerate(cursor.description):
|
||||||
|
this_dict[col[0]] = row[idx]
|
||||||
|
|
||||||
|
return this_dict
|
||||||
|
|
||||||
|
|
||||||
|
####################################################################################################
|
||||||
|
##################################### ФОРМАТИРОВАНИЕ ЗАПРОСОВ ######################################
|
||||||
|
# Форматирование запроса без аргументов
|
||||||
|
def update_format_with_args(sql, parameters: dict):
|
||||||
|
if "XXX" not in sql:
|
||||||
|
sql += " XXX "
|
||||||
|
|
||||||
|
values = ", ".join([
|
||||||
|
f"{item} = ?" for item in parameters
|
||||||
|
])
|
||||||
|
sql = sql.replace("XXX", values)
|
||||||
|
|
||||||
|
return sql, list(parameters.values())
|
||||||
|
|
||||||
|
|
||||||
|
# Форматирование запроса с аргументами
|
||||||
|
def update_format_args(sql, parameters: dict):
|
||||||
|
sql = f"{sql} WHERE "
|
||||||
|
|
||||||
|
sql += " AND ".join([
|
||||||
|
f"{item} = ?" for item in parameters
|
||||||
|
])
|
||||||
|
|
||||||
|
return sql, list(parameters.values())
|
||||||
|
|
||||||
|
|
||||||
|
####################################### ЗАПРОСЫ К БАЗЕ ДАННЫХ ######################################
|
||||||
|
####################################################################################################
|
||||||
|
# Добавление пользователя
|
||||||
|
def add_userx(user_id, user_login, user_name, user_surname, user_fullname):
|
||||||
|
with sqlite3.connect(PATH_DATABASE) as con:
|
||||||
|
con.row_factory = dict_factory
|
||||||
|
con.execute("INSERT INTO storage_users "
|
||||||
|
"(user_id, user_login, user_name, user_surname, user_fullname, user_date, user_unix) "
|
||||||
|
"VALUES (?, ?, ?, ?, ?, ?, ?)",
|
||||||
|
[user_id, user_login, user_name, user_surname, user_fullname, get_date(), get_unix()])
|
||||||
|
con.commit()
|
||||||
|
|
||||||
|
|
||||||
|
# Получение пользователя
|
||||||
|
def get_userx(**kwargs):
|
||||||
|
with sqlite3.connect(PATH_DATABASE) as con:
|
||||||
|
con.row_factory = dict_factory
|
||||||
|
sql = "SELECT * FROM storage_users"
|
||||||
|
sql, parameters = update_format_args(sql, kwargs)
|
||||||
|
return con.execute(sql, parameters).fetchone()
|
||||||
|
|
||||||
|
|
||||||
|
# Получение пользователей
|
||||||
|
def get_usersx(**kwargs):
|
||||||
|
with sqlite3.connect(PATH_DATABASE) as con:
|
||||||
|
con.row_factory = dict_factory
|
||||||
|
sql = "SELECT * FROM storage_users"
|
||||||
|
sql, parameters = update_format_args(sql, kwargs)
|
||||||
|
return con.execute(sql, parameters).fetchall()
|
||||||
|
|
||||||
|
|
||||||
|
# Получение всех пользователей
|
||||||
|
def get_all_usersx():
|
||||||
|
with sqlite3.connect(PATH_DATABASE) as con:
|
||||||
|
con.row_factory = dict_factory
|
||||||
|
sql = "SELECT * FROM storage_users"
|
||||||
|
return con.execute(sql).fetchall()
|
||||||
|
|
||||||
|
|
||||||
|
# Редактирование пользователя
|
||||||
|
def update_userx(user_id, **kwargs):
|
||||||
|
with sqlite3.connect(PATH_DATABASE) as con:
|
||||||
|
con.row_factory = dict_factory
|
||||||
|
sql = f"UPDATE storage_users SET"
|
||||||
|
sql, parameters = update_format_with_args(sql, kwargs)
|
||||||
|
parameters.append(user_id)
|
||||||
|
con.execute(sql + "WHERE user_id = ?", parameters)
|
||||||
|
con.commit()
|
||||||
|
|
||||||
|
|
||||||
|
# Удаление пользователя
|
||||||
|
def delete_userx(**kwargs):
|
||||||
|
with sqlite3.connect(PATH_DATABASE) as con:
|
||||||
|
con.row_factory = dict_factory
|
||||||
|
sql = "DELETE FROM storage_users"
|
||||||
|
sql, parameters = update_format_args(sql, kwargs)
|
||||||
|
con.execute(sql, parameters)
|
||||||
|
con.commit()
|
||||||
|
|
||||||
|
|
||||||
|
######################################## СОЗДАНИЕ БАЗЫ ДАННЫХ ######################################
|
||||||
|
# Создание всех таблиц для Базы Данных
|
||||||
|
def create_dbx():
|
||||||
|
with sqlite3.connect(PATH_DATABASE) as con:
|
||||||
|
con.row_factory = dict_factory
|
||||||
|
|
||||||
|
# Таблица с хранением пользователей
|
||||||
|
if len(con.execute("PRAGMA table_info(storage_users)").fetchall()) == 8:
|
||||||
|
print("DB was found(1/1)")
|
||||||
|
else:
|
||||||
|
con.execute("CREATE TABLE storage_users("
|
||||||
|
"increment INTEGER PRIMARY KEY AUTOINCREMENT, "
|
||||||
|
"user_id INTEGER,"
|
||||||
|
"user_login TEXT,"
|
||||||
|
"user_name TEXT,"
|
||||||
|
"user_surname TEXT,"
|
||||||
|
"user_fullname TEXT,"
|
||||||
|
"user_date TIMESTAMP,"
|
||||||
|
"user_unix INTEGER)")
|
||||||
|
print("DB was not found(1/1) | Creating...")
|
||||||
|
|
||||||
|
con.commit()
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
@@ -0,0 +1,235 @@
|
|||||||
|
# - *- coding: utf- 8 - *-
|
||||||
|
import random
|
||||||
|
import time
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
from aiogram import Bot, types
|
||||||
|
from aiogram.types import InlineKeyboardButton, KeyboardButton
|
||||||
|
|
||||||
|
######################################## AIOGRAM ########################################
|
||||||
|
# Генерация реплай кнопки
|
||||||
|
from tgbot.config import get_admins
|
||||||
|
|
||||||
|
|
||||||
|
def rkb(text):
|
||||||
|
return KeyboardButton(text=text)
|
||||||
|
|
||||||
|
|
||||||
|
# Генерация инлайн кнопки
|
||||||
|
def ikb(text, data=None, url=None, switch=None):
|
||||||
|
if data is not None:
|
||||||
|
return InlineKeyboardButton(text=text, callback_data=data)
|
||||||
|
elif url is not None:
|
||||||
|
return InlineKeyboardButton(text=text, url=url)
|
||||||
|
else:
|
||||||
|
return InlineKeyboardButton(text=text, switch_inline_query=switch)
|
||||||
|
|
||||||
|
|
||||||
|
# Отправка сообщения всем админам
|
||||||
|
async def send_admins(bot: Bot, message, markup=None, not_me=0):
|
||||||
|
for admin in get_admins():
|
||||||
|
try:
|
||||||
|
if str(admin) != str(not_me):
|
||||||
|
await bot.send_message(admin, message, reply_markup=markup, disable_web_page_preview=True)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
# Умная отправка сообщений
|
||||||
|
async def smart_send(bot: Bot, message: types.Message, user_id, text_add=None, reply=None):
|
||||||
|
if message.text is not None:
|
||||||
|
get_text = message.text
|
||||||
|
elif message.caption is not None:
|
||||||
|
get_text = message.caption
|
||||||
|
else:
|
||||||
|
get_text = ""
|
||||||
|
|
||||||
|
if text_add is not None:
|
||||||
|
get_text = text_add.format(get_text)
|
||||||
|
|
||||||
|
if message.photo is not None:
|
||||||
|
await bot.send_photo(user_id, message.photo[-1].file_id, caption=get_text, reply_markup=reply)
|
||||||
|
elif message.video is not None:
|
||||||
|
await bot.send_video(user_id, message.video.file_id, caption=get_text, reply_markup=reply)
|
||||||
|
elif message.document is not None:
|
||||||
|
await bot.send_document(user_id, message.document.file_id, caption=get_text, reply_markup=reply)
|
||||||
|
elif message.audio is not None:
|
||||||
|
await bot.send_audio(user_id, message.audio.file_id, caption=get_text, reply_markup=reply)
|
||||||
|
elif message.voice is not None:
|
||||||
|
await bot.send_voice(user_id, message.voice.file_id, caption=get_text, reply_markup=reply)
|
||||||
|
elif message.animation is not None:
|
||||||
|
await bot.send_animation(user_id, message.animation.file_id, reply_markup=reply)
|
||||||
|
elif message.sticker is not None:
|
||||||
|
await bot.send_sticker(user_id, message.sticker.file_id, reply_markup=reply)
|
||||||
|
elif message.dice is not None:
|
||||||
|
await bot.send_dice(user_id, message.dice.emoji, reply_markup=reply)
|
||||||
|
elif message.location is not None:
|
||||||
|
await bot.send_location(user_id, latitude=message.location.latitude, longitude=message.location.longitude,
|
||||||
|
reply_markup=reply)
|
||||||
|
else:
|
||||||
|
await bot.send_message(user_id, get_text)
|
||||||
|
|
||||||
|
|
||||||
|
######################################## ПРОЧЕЕ ########################################
|
||||||
|
# Очистка HTML тэгов
|
||||||
|
def clear_html(get_text: str):
|
||||||
|
if get_text is not None:
|
||||||
|
if "<" in get_text: get_text = get_text.replace("<", "*")
|
||||||
|
if ">" in get_text: get_text = get_text.replace(">", "*")
|
||||||
|
|
||||||
|
return get_text
|
||||||
|
|
||||||
|
|
||||||
|
# Очистка пробелов в списке
|
||||||
|
def clear_list(get_list: list):
|
||||||
|
while "" in get_list: get_list.remove("")
|
||||||
|
while " " in get_list: get_list.remove(" ")
|
||||||
|
while "," in get_list: get_list.remove(",")
|
||||||
|
while "\r" in get_list: get_list.remove("\r")
|
||||||
|
|
||||||
|
return get_list
|
||||||
|
|
||||||
|
|
||||||
|
# Разбив списка на несколько частей
|
||||||
|
def split_messages(get_list: list, count: int):
|
||||||
|
return [get_list[i:i + count] for i in range(0, len(get_list), count)]
|
||||||
|
|
||||||
|
|
||||||
|
# Получение даты
|
||||||
|
def get_date():
|
||||||
|
this_date = datetime.today().replace(microsecond=0)
|
||||||
|
this_date = this_date.strftime("%d.%m.%Y %H:%M:%S")
|
||||||
|
|
||||||
|
return this_date
|
||||||
|
|
||||||
|
|
||||||
|
# Получение юникс даты
|
||||||
|
def get_unix():
|
||||||
|
return int(time.time())
|
||||||
|
|
||||||
|
|
||||||
|
# Генерация пароля
|
||||||
|
def generate_password(len_password: int):
|
||||||
|
passwd = list("1234567890abcdefghigklmnopqrstuvyxwzABCDEFGHIGKLMNOPQRSTUVYXWZ")
|
||||||
|
random.shuffle(passwd)
|
||||||
|
random_chars = "".join([random.choice(passwd) for x in range(len_password)])
|
||||||
|
|
||||||
|
return random_chars
|
||||||
|
|
||||||
|
|
||||||
|
# Корректный вывод времени
|
||||||
|
def convert_times(get_time, get_type="day"):
|
||||||
|
get_time = int(get_time)
|
||||||
|
|
||||||
|
if get_type == "second":
|
||||||
|
get_list = ["секунда", "секунды", "секунд"]
|
||||||
|
elif get_type == "minute":
|
||||||
|
get_list = ["минута", "минуты", "минут"]
|
||||||
|
elif get_type == "hour":
|
||||||
|
get_list = ["час", "часа", "часов"]
|
||||||
|
elif get_type == "day":
|
||||||
|
get_list = ["день", "дня", "дней"]
|
||||||
|
elif get_type == "month":
|
||||||
|
get_list = ["месяц", "месяца", "месяцев"]
|
||||||
|
else:
|
||||||
|
get_list = ["год", "года", "лет"]
|
||||||
|
|
||||||
|
if get_time % 10 == 1 and get_time % 100 != 11:
|
||||||
|
count = 0
|
||||||
|
elif 2 <= get_time % 10 <= 4 and (get_time % 100 < 10 or get_time % 100 >= 20):
|
||||||
|
count = 1
|
||||||
|
else:
|
||||||
|
count = 2
|
||||||
|
|
||||||
|
return f"{get_time} {get_list[count]}"
|
||||||
|
|
||||||
|
|
||||||
|
######################################## ЧИСЛА ########################################
|
||||||
|
# Конвертация числа в вещественное
|
||||||
|
def to_float(get_number, remains=2):
|
||||||
|
if "," in str(get_number):
|
||||||
|
get_number = str(get_number).replace(",", ".")
|
||||||
|
|
||||||
|
if "." in get_number:
|
||||||
|
get_last = get_number.split(".")
|
||||||
|
|
||||||
|
if get_last[1].endswith("0"):
|
||||||
|
while True:
|
||||||
|
if get_number.endswith("0"):
|
||||||
|
get_number = get_number[:-1]
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
|
||||||
|
get_number = round(float(get_number), remains)
|
||||||
|
|
||||||
|
if str(float(get_number)).split(".")[1] == "0":
|
||||||
|
get_number = int(get_number)
|
||||||
|
else:
|
||||||
|
get_number = float(get_number)
|
||||||
|
|
||||||
|
return get_number
|
||||||
|
|
||||||
|
|
||||||
|
# Конвертация числа в целочисленное
|
||||||
|
def to_int(get_number):
|
||||||
|
if "," in get_number:
|
||||||
|
get_number = get_number.replace(",", ".")
|
||||||
|
|
||||||
|
get_number = int(round(float(get_number)))
|
||||||
|
|
||||||
|
return get_number
|
||||||
|
|
||||||
|
|
||||||
|
# Проверка числа на вещественное
|
||||||
|
def is_number(get_number):
|
||||||
|
if get_number.isdigit():
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
if "," in str(get_number): get_number = str(get_number).replace(",", ".")
|
||||||
|
|
||||||
|
try:
|
||||||
|
float(get_number)
|
||||||
|
return False
|
||||||
|
except ValueError:
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
# Преобразование длинных вещественных чисел в читаемый вид
|
||||||
|
def show_floats(amount):
|
||||||
|
return f"{float(amount):.{len(str(amount).split('.')[1])}f}"
|
||||||
|
|
||||||
|
|
||||||
|
# Форматирование чисел в читаемый вид
|
||||||
|
def format_rate(rate, around=False):
|
||||||
|
rate = str(round(float(rate), 2))
|
||||||
|
|
||||||
|
if "," in rate:
|
||||||
|
rate = float(rate.replace(",", "."))
|
||||||
|
|
||||||
|
len_rate = str(int(float(rate)))
|
||||||
|
|
||||||
|
if len(len_rate) == 3:
|
||||||
|
get_rate = str(len_rate)
|
||||||
|
elif len(len_rate) == 4:
|
||||||
|
get_rate = f"{len_rate[0]} {len_rate[1:]}"
|
||||||
|
elif len(len_rate) == 5:
|
||||||
|
get_rate = f"{len_rate[0:2]} {len_rate[2:]}"
|
||||||
|
elif len(len_rate) == 6:
|
||||||
|
get_rate = f"{len_rate[0:3]} {len_rate[3:]}"
|
||||||
|
elif len(len_rate) == 7:
|
||||||
|
get_rate = f"{len_rate[0:1]} {len_rate[1:4]} {len_rate[4:]}"
|
||||||
|
elif len(len_rate) == 8:
|
||||||
|
get_rate = f"{len_rate[0:2]} {len_rate[2:5]} {len_rate[5:]}"
|
||||||
|
elif len(len_rate) == 9:
|
||||||
|
get_rate = f"{len_rate[0:3]} {len_rate[3:6]} {len_rate[6:]}"
|
||||||
|
elif len(len_rate) == 10:
|
||||||
|
get_rate = f"{len_rate[0:1]} {len_rate[1:4]} {len_rate[4:7]} {len_rate[7:]}"
|
||||||
|
else:
|
||||||
|
get_rate = 0
|
||||||
|
|
||||||
|
if not around:
|
||||||
|
if "." in rate:
|
||||||
|
dot_amount = rate.find(".")
|
||||||
|
get_rate += f"{rate[dot_amount:]}"
|
||||||
|
|
||||||
|
return get_rate
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
# - *- coding: utf- 8 - *-
|
||||||
|
from aiogram import Bot
|
||||||
|
from aiogram.types import BotCommand, BotCommandScopeChat, BotCommandScopeDefault
|
||||||
|
|
||||||
|
from tgbot.config import get_admins
|
||||||
|
|
||||||
|
# Команды для юзеров
|
||||||
|
user_commands = [
|
||||||
|
BotCommand(command="start", description="♻ Перезапустить бота"),
|
||||||
|
BotCommand(command="inline", description="🌀 Получить Inline клавиатуру"),
|
||||||
|
]
|
||||||
|
|
||||||
|
# Команды для админов
|
||||||
|
admin_commands = [
|
||||||
|
BotCommand(command="start", description="♻ Перезапустить бота"),
|
||||||
|
BotCommand(command="inline", description="🌀 Получить Inline клавиатуру"),
|
||||||
|
BotCommand(command="log", description="🖨 Получить Логи"),
|
||||||
|
BotCommand(command="db", description="📦 Получить Базу Данных"),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
# Установка команд
|
||||||
|
async def set_commands(bot: Bot):
|
||||||
|
await bot.set_my_commands(user_commands, scope=BotCommandScopeDefault())
|
||||||
|
|
||||||
|
for admin in get_admins():
|
||||||
|
try:
|
||||||
|
await bot.set_my_commands(admin_commands, scope=BotCommandScopeChat(chat_id=admin))
|
||||||
|
except:
|
||||||
|
pass
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
# - *- coding: utf- 8 - *-
|
||||||
|
from aiogram.dispatcher.filters import BaseFilter
|
||||||
|
from aiogram.types import Message
|
||||||
|
|
||||||
|
from tgbot.config import get_admins
|
||||||
|
|
||||||
|
|
||||||
|
# Проверка на админа
|
||||||
|
class IsAdmin(BaseFilter):
|
||||||
|
async def __call__(self, message: Message):
|
||||||
|
if message.from_user.id in get_admins():
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
# - *- coding: utf- 8 - *-
|
||||||
|
import logging as bot_logger
|
||||||
|
|
||||||
|
import colorlog
|
||||||
|
|
||||||
|
from tgbot.config import PATH_LOGS
|
||||||
|
|
||||||
|
# Формат логгирования
|
||||||
|
log_formatter_file = bot_logger.Formatter("%(levelname)s | %(asctime)s | %(filename)s:%(lineno)d | %(message)s")
|
||||||
|
log_formatter_console = colorlog.ColoredFormatter(
|
||||||
|
"%(purple)s%(levelname)s %(blue)s|%(purple)s %(asctime)s %(blue)s|%(purple)s %(filename)s:%(lineno)d %(blue)s|%(purple)s %(message)s%(red)s",
|
||||||
|
datefmt="%d-%m-%Y %H:%M:%S",
|
||||||
|
)
|
||||||
|
|
||||||
|
# Логгирование в файл logs.log
|
||||||
|
file_handler = bot_logger.FileHandler(PATH_LOGS, "w", "utf-8")
|
||||||
|
file_handler.setFormatter(log_formatter_file)
|
||||||
|
file_handler.setLevel(bot_logger.INFO)
|
||||||
|
|
||||||
|
# Логгирование в консоль
|
||||||
|
console_handler = bot_logger.StreamHandler()
|
||||||
|
console_handler.setFormatter(log_formatter_console)
|
||||||
|
console_handler.setLevel(bot_logger.CRITICAL)
|
||||||
|
|
||||||
|
# Подключение настроек логгирования
|
||||||
|
bot_logger.basicConfig(
|
||||||
|
format="%(levelname)s | %(asctime)s | %(filename)s:%(lineno)d | %(message)s",
|
||||||
|
handlers=[
|
||||||
|
file_handler,
|
||||||
|
console_handler
|
||||||
|
]
|
||||||
|
)
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
# - *- coding: utf- 8 - *-
|
||||||
|
from textwrap import dedent
|
||||||
|
|
||||||
|
from aiogram.dispatcher.fsm.context import FSMContext
|
||||||
|
|
||||||
|
from tgbot.services.api_session import RequestsSession
|
||||||
|
|
||||||
|
ded = dedent
|
||||||
|
FSM = FSMContext
|
||||||
|
RS = RequestsSession
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
# - *- coding: utf- 8 - *-
|
||||||
|
from aiogram import Bot
|
||||||
|
from aiogram.types import FSInputFile
|
||||||
|
|
||||||
|
from tgbot.config import get_admins, PATH_DATABASE
|
||||||
|
from tgbot.utils.const_functions import get_date, send_admins
|
||||||
|
|
||||||
|
|
||||||
|
# Выполнение функции после запуска бота (рассылка админам о запуске бота)
|
||||||
|
async def startup_notify(bot: Bot):
|
||||||
|
if len(get_admins()) >= 1:
|
||||||
|
await send_admins(bot, "<b>✅ Бот был запущен</b>")
|
||||||
|
|
||||||
|
|
||||||
|
# Автоматические бэкапы БД
|
||||||
|
async def autobackup(bot: Bot):
|
||||||
|
for admin in get_admins():
|
||||||
|
try:
|
||||||
|
await bot.send_document(admin,
|
||||||
|
FSInputFile(PATH_DATABASE),
|
||||||
|
caption=f"<b>📦 AUTOBACKUP</b>\n"
|
||||||
|
f"<code>🕰 {get_date()}</code>")
|
||||||
|
except:
|
||||||
|
pass
|
||||||
Reference in New Issue
Block a user