diff --git a/.env.example b/.env.example
index 18f43b8..031d246 100644
--- a/.env.example
+++ b/.env.example
@@ -1,6 +1,6 @@
TELEGRAM_BOT_TOKEN='123456789:XXXXXXXXXXXXXXXXXXXXXXXXXXXX'
-TELEGRAM_ADMINS_ID='123456789,987654321'
+TELEGRAM_ADMINS_ID=[123456789 , 987654321]
MARZBAN_ADDRESS='https://sub.domain.com:port'
MARZBAN_USERNAME='sudo_username'
MARZBAN_PASSWORD='sudo_password'
-EXCLUDED_MONITORINGS='NODE_NAME_ONE,NODE_NAME_TWO'
\ No newline at end of file
+EXCLUDED_MONITORINGS=[NODE_NAME_ONE , NODE_NAME_TWO]
\ No newline at end of file
diff --git a/jobs/node_monitoring.py b/jobs/node_monitoring.py
index 44292fa..88ab577 100644
--- a/jobs/node_monitoring.py
+++ b/jobs/node_monitoring.py
@@ -8,10 +8,9 @@
from db.crud import SettingManager, TokenManager
from models.setting import SettingKeys
-from utils import report
-from utils.config import MARZBAN_ADDRESS, EXCLUDED_MONITORINGS
+from utils import report, EnvSettings
-panel = MarzbanAPI(base_url=MARZBAN_ADDRESS)
+panel = MarzbanAPI(base_url=EnvSettings.MARZBAN_ADDRESS)
async def node_checker():
@@ -29,7 +28,7 @@ async def node_checker():
nodes = await panel.get_nodes(token.token)
anti_spam = False
for node in nodes:
- if node.name in EXCLUDED_MONITORINGS:
+ if node.name in EnvSettings.EXCLUDED_MONITORINGS:
continue
if node.status in ["connecting", "error"]:
@@ -47,7 +46,7 @@ async def node_checker():
try:
await panel.reconnect_node(node.id, token.token)
await report.node_restart(node, True)
- except (ConnectionError, TimeoutError): # Omit the variable if not used
+ except (ConnectionError, TimeoutError):
await report.node_restart(node, False)
if anti_spam:
diff --git a/jobs/scheduler.py b/jobs/scheduler.py
index 3cafe43..115976a 100644
--- a/jobs/scheduler.py
+++ b/jobs/scheduler.py
@@ -6,7 +6,7 @@
from apscheduler.triggers.interval import IntervalTrigger
from jobs.token_updater import token_update
from jobs.node_monitoring import node_checker
-from utils.log import logger
+from utils import logger
scheduler = AsyncIOScheduler()
diff --git a/jobs/token_updater.py b/jobs/token_updater.py
index f996c7a..690d847 100644
--- a/jobs/token_updater.py
+++ b/jobs/token_updater.py
@@ -5,23 +5,22 @@
import httpx
from marzban import MarzbanAPI
-from utils.config import MARZBAN_PASSWORD, MARZBAN_USERNAME, MARZBAN_ADDRESS
-from utils.log import logger
+from utils import EnvSettings, logger
from db.crud import TokenManager
from models import TokenUpsert
async def token_update() -> bool:
"""Add or update Marzban panel token every X time."""
- if not MARZBAN_USERNAME or not MARZBAN_PASSWORD:
+ if not EnvSettings.MARZBAN_USERNAME or not EnvSettings.MARZBAN_PASSWORD:
logger.error("MARZBAN_USERNAME or MARZBAN_PASSWORD is not set.")
return False
- api = MarzbanAPI(base_url=MARZBAN_ADDRESS)
+ api = MarzbanAPI(base_url=EnvSettings.MARZBAN_ADDRESS)
try:
get_token = await api.get_token(
- username=MARZBAN_USERNAME, password=MARZBAN_PASSWORD
+ username=EnvSettings.MARZBAN_USERNAME, password=EnvSettings.MARZBAN_PASSWORD
)
if get_token and get_token.access_token:
diff --git a/main.py b/main.py
index de2c9bf..6c7dc5b 100644
--- a/main.py
+++ b/main.py
@@ -12,39 +12,40 @@
from jobs import stop_scheduler, start_scheduler
from middlewares.auth import CheckAdminAccess
from routers import setup_routers
-from utils.config import TELEGRAM_BOT_TOKEN
-from utils.log import logger
-from utils.statedb import storage
+from utils import EnvSettings, logger, storage
async def on_startup() -> None:
"""Function to execute during bot startup."""
- logger.info("Bot is starting up...")
+ logger.info("HolderBot is starting up...")
- logger.info("Starting scheduler...")
+ logger.info(
+ "Admin IDs: %s", ", ".join(map(str, EnvSettings.TELEGRAM_ADMINS_ID))
+ ) # Log admin IDs
+ logger.info("Starting scheduler for HolderBot...")
run_job = await start_scheduler() # Start scheduled tasks
if not run_job:
raise SystemExit(
- logger.critical("Stopping the bot due to scheduler startup failure.")
+ logger.critical("Stopping HolderBot due to scheduler startup failure.")
) # Stop the bot if scheduler fails
- logger.info("Scheduler is running.")
- logger.info("Bot is up and running!")
+ logger.info("Scheduler is running for HolderBot.")
+ logger.info("HolderBot is up and running!")
async def on_shutdown() -> None:
"""Function to execute during bot shutdown."""
- logger.info("Bot is shutting down...")
+ logger.info("HolderBot is shutting down...")
logger.info("Stopping scheduler...")
await stop_scheduler() # Stop scheduled tasks
logger.info("Scheduler has stopped.")
- logger.info("Bot has shut down successfully.")
+ logger.info("HolderBot has shut down successfully.")
async def main() -> None:
"""Function to run aiogram bot."""
bot = Bot(
- token=TELEGRAM_BOT_TOKEN,
+ token=EnvSettings.TELEGRAM_BOT_TOKEN,
default=DefaultBotProperties(
parse_mode=ParseMode.HTML, link_preview_is_disabled=True
),
@@ -65,18 +66,21 @@ async def main() -> None:
# Start polling the bot
try:
+ bot_info = await bot.get_me()
+ logger.info("HolderBot [@%s] is starting to poll messages...", bot_info.username)
await dp.start_polling(bot)
except (ConnectionError, TimeoutError) as conn_err:
logger.error("A connection error occurred while polling: %s", conn_err)
except Exception as e: # pylint: disable=broad-except
- logger.error("An error occurred while polling: %s", e)
+ logger.error("An error occurred while polling HolderBot: %s", e)
if __name__ == "__main__":
try:
# Run the main function using asyncio
+ logger.info("Running HolderBot...")
asyncio.run(main())
except KeyboardInterrupt:
- logger.warning("Bot stopped by user.")
+ logger.warning("HolderBot stopped by user.")
except Exception as e: # pylint: disable=broad-except
- logger.error("An unexpected error occurred: %s", e)
+ logger.error("An unexpected error occurred in HolderBot: %s", e)
diff --git a/middlewares/auth.py b/middlewares/auth.py
index 2db27a4..cdfde15 100644
--- a/middlewares/auth.py
+++ b/middlewares/auth.py
@@ -6,7 +6,7 @@
from aiogram import BaseMiddleware
from aiogram.types import Update
-from utils import logger, storage, config
+from utils import logger, storage, EnvSettings
# pylint: disable=too-few-public-methods
@@ -38,7 +38,7 @@ async def __call__(
logger.warning("Received update without user information!")
return None
- if user.id not in config.TELEGRAM_ADMINS_ID:
+ if user.id not in EnvSettings.TELEGRAM_ADMINS_ID:
logger.warning("Blocked %s", user.username or user.first_name)
return None
diff --git a/routers/base.py b/routers/base.py
index 3fbf64c..d085d0e 100644
--- a/routers/base.py
+++ b/routers/base.py
@@ -8,9 +8,7 @@
from aiogram.filters.command import CommandStart, Command
from aiogram.fsm.context import FSMContext
-from utils.statedb import storage
-from utils.lang import MessageTexts
-from utils.keys import BotKeyboards
+from utils import MessageTexts, storage, BotKeyboards
from models import PagesCallbacks, PagesActions
router = Router()
diff --git a/routers/node.py b/routers/node.py
index d15c11a..c63655e 100644
--- a/routers/node.py
+++ b/routers/node.py
@@ -7,8 +7,7 @@
from aiogram.types import CallbackQuery
from db.crud import SettingManager
-from utils.lang import MessageTexts
-from utils.keys import BotKeyboards
+from utils import MessageTexts, BotKeyboards
from models import (
PagesActions,
PagesCallbacks,
diff --git a/routers/user.py b/routers/user.py
index bc56aec..9438361 100644
--- a/routers/user.py
+++ b/routers/user.py
@@ -10,11 +10,15 @@
from marzban import ProxyInbound
-from utils.config import MARZBAN_USERNAME
-from utils.lang import MessageTexts
-from utils.keys import BotKeyboards
-from utils.statedb import storage
-from utils import panel, text_info, helpers
+from utils import (
+ panel,
+ text_info,
+ helpers,
+ MessageTexts,
+ storage,
+ EnvSettings,
+ BotKeyboards,
+)
from models import (
PagesActions,
PagesCallbacks,
@@ -154,10 +158,12 @@ async def user_create_owner_select(
"""
await state.update_data(admin=callback_data.username)
inbounds = await panel.get_inbounds()
+ tags = [item['tag'] for sublist in inbounds.values() for item in sublist]
await state.update_data(inbounds=inbounds)
+ await state.update_data(selected_inbounds=tags)
return await callback.message.edit_text(
text=MessageTexts.ASK_CREATE_USER_INBOUNDS,
- reply_markup=BotKeyboards.inbounds(inbounds),
+ reply_markup=BotKeyboards.inbounds(inbounds, tags),
)
@@ -244,7 +250,7 @@ async def user_create_inbounds_save(callback: CallbackQuery, state: FSMContext):
)
if new_user:
- if data["admin"] != MARZBAN_USERNAME:
+ if data["admin"] != EnvSettings.MARZBAN_USERNAME:
await panel.set_owner(data["admin"], new_user.username)
qr_bytes = await helpers.create_qr(new_user.subscription_url)
await callback.message.answer_photo(
@@ -258,3 +264,8 @@ async def user_create_inbounds_save(callback: CallbackQuery, state: FSMContext):
)
await callback.message.delete()
+ await state.clear()
+ new_message = await callback.message.answer(
+ text=MessageTexts.START, reply_markup=BotKeyboards.home()
+ )
+ return await storage.clear_and_add_message(new_message)
diff --git a/routers/users.py b/routers/users.py
index 4e21225..33f6b08 100644
--- a/routers/users.py
+++ b/routers/users.py
@@ -14,9 +14,8 @@
BotActions,
UserInboundsCallbacks,
)
-from utils.lang import MessageTexts
-from utils.keys import BotKeyboards
-from utils import panel, helpers
+
+from utils import panel, helpers, BotKeyboards, MessageTexts
router = Router()
diff --git a/utils/__init__.py b/utils/__init__.py
index bcd7730..78ec732 100644
--- a/utils/__init__.py
+++ b/utils/__init__.py
@@ -2,7 +2,17 @@
This module imports necessary components for database access and logging.
"""
-from .statedb import storage
-from .log import logger
+from .statedb import SQLAlchemyStorage
+from .log import BotLogger
+from .config import EnvFile
+from .lang import MessageTextsFile, KeyboardTextsFile
+from .keys import BotKeyboards
-__all__ = ["storage", "logger"]
+logger = BotLogger("HolderBot").get_logger()
+EnvSettings = EnvFile()
+MessageTexts = MessageTextsFile()
+KeyboardTexts = KeyboardTextsFile()
+storage = SQLAlchemyStorage()
+
+
+__all__ = ["storage", "logger", "KeyboardTexts", "MessageTexts", "BotKeyboards"]
diff --git a/utils/config.py b/utils/config.py
index d567e25..cb795be 100644
--- a/utils/config.py
+++ b/utils/config.py
@@ -4,45 +4,19 @@
It ensures that all required settings are provided and checks for missing values.
"""
-from decouple import config
+from pydantic_settings import BaseSettings, SettingsConfigDict
-# Function to check if a required configuration value is missing
-def require_setting(setting_name, value):
- """
- Ensures that a required setting is provided and not empty.
- """
- if not value:
- raise ValueError(
- f"The '{setting_name}' setting is required and cannot be empty."
- )
+class EnvFile(BaseSettings):
+ """.env file config data"""
+ model_config: SettingsConfigDict = SettingsConfigDict(
+ env_file=".env", extra="ignore"
+ )
-# Telegram Bot Settings
-TELEGRAM_BOT_TOKEN = config("TELEGRAM_BOT_TOKEN", cast=str) # required
-require_setting("TELEGRAM_BOT_TOKEN", TELEGRAM_BOT_TOKEN)
-
-TELEGRAM_ADMINS_ID = config(
- "TELEGRAM_ADMINS_ID",
- default="",
- cast=lambda v: [
- int(i) for i in filter(str.isdigit, (s.strip() for s in v.split(",")))
- ],
-) # required
-require_setting("TELEGRAM_ADMINS_ID", TELEGRAM_ADMINS_ID)
-
-# Marzban Panel Settings
-MARZBAN_USERNAME = config("MARZBAN_USERNAME", default="", cast=str) # required
-require_setting("MARZBAN_USERNAME", MARZBAN_USERNAME)
-
-MARZBAN_PASSWORD = config("MARZBAN_PASSWORD", default="", cast=str) # required
-require_setting("MARZBAN_PASSWORD", MARZBAN_PASSWORD)
-
-MARZBAN_ADDRESS = config("MARZBAN_ADDRESS", default="", cast=str) # required
-require_setting("MARZBAN_ADDRESS", MARZBAN_ADDRESS)
-
-EXCLUDED_MONITORINGS = [
- x.strip()
- for x in config("EXCLUDED_MONITORINGS", default="", cast=str).split(",")
- if x.strip()
-]
+ TELEGRAM_BOT_TOKEN: str
+ TELEGRAM_ADMINS_ID: list[int]
+ MARZBAN_USERNAME: str
+ MARZBAN_PASSWORD: str
+ MARZBAN_ADDRESS: str
+ EXCLUDED_MONITORINGS: list[str] = []
diff --git a/utils/helpers.py b/utils/helpers.py
index 544d821..02d14be 100644
--- a/utils/helpers.py
+++ b/utils/helpers.py
@@ -9,8 +9,7 @@
import httpx
from marzban import UserModify, UserResponse
from models import AdminActions
-from utils import panel
-from utils.log import logger
+from utils import logger, panel
async def create_qr(text: str) -> bytes:
diff --git a/utils/keys.py b/utils/keys.py
index 8bcddcd..1d3fd75 100644
--- a/utils/keys.py
+++ b/utils/keys.py
@@ -9,7 +9,7 @@
from aiogram.utils.keyboard import InlineKeyboardBuilder
from marzban import ProxyInbound, Admin, UserResponse
-from utils.lang import KeyboardTexts
+from utils.lang import KeyboardTextsFile
from models import (
PagesActions,
PagesCallbacks,
@@ -21,6 +21,8 @@
BotActions,
)
+KeyboardTexts = KeyboardTextsFile()
+
class BotKeyboards:
"""
diff --git a/utils/lang.py b/utils/lang.py
index 2591695..d71b948 100644
--- a/utils/lang.py
+++ b/utils/lang.py
@@ -2,64 +2,78 @@
This module contains constants and texts used in the HolderBot.
"""
-from enum import Enum
+from pydantic_settings import BaseSettings, SettingsConfigDict
-# Module constants
-VERSION = "0.2.3"
-OWNER = "@ErfJabs"
-
-class KeyboardTexts(str, Enum):
+class KeyboardTextsFile(BaseSettings):
"""Keyboard texts used in the bot."""
- HOME = "π Back to home"
- USER_CREATE = "π€ User Create"
- NODE_MONITORING = "π Node Monitoring"
- ACTIVE = "β
Active"
- ON_HOLD = "βΈοΈ On hold"
- FINISH = "βοΈ Finish"
- NODE_MONITORING_CHECKER = "𧨠Checker"
- NODE_MONITORING_AUTO_RESTART = "π AutoRestart"
- USERS_MENU = "π₯ Users"
- USERS_ADD_INBOUND = "β Add inbound"
- USERS_DELETE_INBOUND = "β Delete inbound"
- USER_CREATE_LINK_COPY = "To copy the link, please click."
+ model_config: SettingsConfigDict = SettingsConfigDict(
+ env_file=".env", extra="ignore"
+ )
+
+ HOME: str = "π Back to home"
+ USER_CREATE: str = "π€ User Create"
+ NODE_MONITORING: str = "π Node Monitoring"
+ ACTIVE: str = "β
Active"
+ ON_HOLD: str = "βΈοΈ On hold"
+ FINISH: str = "βοΈ Finish"
+ NODE_MONITORING_CHECKER: str = "𧨠Checker"
+ NODE_MONITORING_AUTO_RESTART: str = "π AutoRestart"
+ USERS_MENU: str = "π₯ Users"
+ USERS_ADD_INBOUND: str = "β Add inbound"
+ USERS_DELETE_INBOUND: str = "β Delete inbound"
+ USER_CREATE_LINK_COPY: str = "To copy the link, please click."
-class MessageTexts(str, Enum):
+class MessageTextsFile(BaseSettings):
"""Message texts used in the bot."""
- START = f"Welcome to HolderBot π€ [{VERSION}]\nDeveloped and designed by {OWNER}"
- VERSION = f"β‘οΈ Current Version: {VERSION}
"
- ASK_CREATE_USER_BASE_USERNAME = "π€ Please enter the user base name"
- ASK_CREATE_USER_START_NUMBER = "π’ Please enter the starting user number"
- ASK_CREATE_USER_HOW_MUCH = "π₯ How many users would you like to create?"
- ASK_CREATE_USER_DATA_LIMIT = "π Please enter the data limit in GB"
- ASK_CREATE_USER_DATE_LIMIT = "π
Please enter the date limit in days"
- ASK_CREATE_USER_STATUS = "π Select the user status"
- ASK_CREATE_ADMIN_USERNAME = "π€ Select the owner admin"
- ASK_CREATE_USER_INBOUNDS = "π Select the user inbounds"
- JUST_NUMBER = "π’ Please enter numbers only"
- NONE_USER_INBOUNDS = "β οΈ Please select an inbound first"
- USER_INFO = (
+ model_config: SettingsConfigDict = SettingsConfigDict(
+ env_file=".env", extra="ignore"
+ )
+
+ VERSION_NUMBER: str = "0.2.3"
+ OWNER_ID: str = "@ErfJabs"
+
+ START: str = (
+ f"Welcome to HolderBot π€ [{VERSION_NUMBER}]\n"
+ f"Developed and designed by {OWNER_ID}"
+ )
+ VERSION: str = f"β‘οΈ Current Version: {VERSION_NUMBER}
"
+ ASK_CREATE_USER_BASE_USERNAME: str = "π€ Please enter the user base name"
+ ASK_CREATE_USER_START_NUMBER: str = (
+ "π’ Please enter the starting user number"
+ )
+ ASK_CREATE_USER_HOW_MUCH: str = "π₯ How many users would you like to create?"
+ ASK_CREATE_USER_DATA_LIMIT: str = "π Please enter the data limit in GB"
+ ASK_CREATE_USER_DATE_LIMIT: str = "π
Please enter the date limit in days"
+ ASK_CREATE_USER_STATUS: str = "π Select the user status"
+ ASK_CREATE_ADMIN_USERNAME: str = "π€ Select the owner admin"
+ ASK_CREATE_USER_INBOUNDS: str = "π Select the user inbounds"
+ JUST_NUMBER: str = "π’ Please enter numbers only"
+ NONE_USER_INBOUNDS: str = "β οΈ Please select an inbound first"
+ USER_INFO: str = (
"{status_emoji} Username: {username}
\n"
"π Data limit: {data_limit}
GB\n"
"π
Date limit: {date_limit}
days\n"
"π Subscription: {subscription}"
)
- NODE_ERROR = (
+ NODE_ERROR: str = (
"π Node: {name}
\n"
"π IP: {ip}
\n"
"πͺ Message: {message}
"
)
- NODE_AUTO_RESTART_DONE = "β
{name}
auto restart is Done!"
- NODE_AUTO_RESTART_ERROR = "β {name}
auto restart is Wrong!"
- NODE_MONITORING_MENU = (
+ NODE_AUTO_RESTART_DONE: str = "β
{name}
auto restart is Done!"
+ NODE_AUTO_RESTART_ERROR: str = (
+ "β {name}
auto restart is Wrong!"
+ )
+ NODE_MONITORING_MENU: str = (
"𧨠Checker is {checker}
\n"
"π AutoRestart is {auto_restart}
"
)
- USERS_MENU = "π₯ What do you need?"
- USERS_INBOUND_SELECT = "π Select Your Inbound:"
- WORKING = "β³"
- USERS_INBOUND_SUCCESS_UPDATED = "β
Users Inbounds is Updated!"
- USERS_INBOUND_ERROR_UPDATED = "β Users Inbounds not Updated!"
+ USERS_MENU: str = "π₯ What do you need?"
+ USERS_INBOUND_SELECT: str = "π Select Your Inbound:"
+ WORKING: str = "β³"
+ USERS_INBOUND_SUCCESS_UPDATED: str = "β
Users Inbounds is Updated!"
+ USERS_INBOUND_ERROR_UPDATED: str = "β Users Inbounds not Updated!"
diff --git a/utils/log.py b/utils/log.py
index 62b1c89..9d2c73c 100644
--- a/utils/log.py
+++ b/utils/log.py
@@ -8,30 +8,63 @@
import logging
-def setup_logger(bot_name, level=logging.INFO):
+class BotLogger:
"""
- Set up a logger for the specified bot.
+ A class to set up and manage a logger for the bot.
+ This class allows logging to both the console and a file.
"""
- bot_logger = logging.getLogger(bot_name)
- bot_logger.setLevel(level)
- console_handler = logging.StreamHandler()
- console_handler.setLevel(logging.DEBUG)
+ def __init__(self, bot_name: str, level: int = logging.INFO):
+ """
+ Initialize the logger for the specified bot.
- file_handler = logging.FileHandler(f"data/{bot_name}.log")
- file_handler.setLevel(logging.INFO)
+ Args:
+ bot_name (str): The name of the bot for which the logger is set up.
+ level (int): The logging level (default is INFO).
+ """
+ self.bot_name = bot_name
+ self.level = level
+ self.bot_logger = logging.getLogger(bot_name)
+ self.bot_logger.setLevel(level)
+ self._setup_handlers()
- formatter = logging.Formatter(
- f"%(asctime)-25s | {bot_name} | %(levelname)-8s | %(message)s"
- )
- console_handler.setFormatter(formatter)
- file_handler.setFormatter(formatter)
+ def _setup_handlers(self):
+ """
+ Set up the console and file handlers for logging.
+ """
+ # Console handler
+ console_handler = logging.StreamHandler()
+ console_handler.setLevel(logging.DEBUG)
- bot_logger.addHandler(console_handler)
- bot_logger.addHandler(file_handler)
+ # File handler
+ file_handler = logging.FileHandler(f"data/{self.bot_name}.log")
+ file_handler.setLevel(logging.INFO)
- return bot_logger
+ # Formatter for both handlers
+ formatter = logging.Formatter(
+ f"%(asctime)-25s | {self.bot_name} | %(levelname)-8s | %(message)s"
+ )
+ console_handler.setFormatter(formatter)
+ file_handler.setFormatter(formatter)
+ # Add handlers to the logger
+ self.bot_logger.addHandler(console_handler)
+ self.bot_logger.addHandler(file_handler)
-# Initialize the logger for HolderBot
-logger = setup_logger("HolderBot")
+ def get_logger(self):
+ """
+ Get the configured logger instance.
+
+ Returns:
+ logging.Logger: The configured logger instance.
+ """
+ return self.bot_logger
+
+ def set_log_level(self, level: int):
+ """
+ Set the logging level for the logger.
+
+ Args:
+ level (int): The logging level to set.
+ """
+ self.bot_logger.setLevel(level)
diff --git a/utils/panel.py b/utils/panel.py
index 5cdb09f..bb64283 100644
--- a/utils/panel.py
+++ b/utils/panel.py
@@ -14,10 +14,9 @@
UserModify,
)
from db import TokenManager
-from utils.config import MARZBAN_ADDRESS
-from utils.log import logger
+from utils import EnvSettings, logger
-marzban_panel = MarzbanAPI(MARZBAN_ADDRESS, timeout=30.0, verify=False)
+marzban_panel = MarzbanAPI(EnvSettings.MARZBAN_ADDRESS, timeout=30.0, verify=False)
async def get_inbounds() -> dict[str, list[ProxyInbound]]:
diff --git a/utils/report.py b/utils/report.py
index 31b4e7f..79d2622 100644
--- a/utils/report.py
+++ b/utils/report.py
@@ -9,12 +9,11 @@
from marzban import NodeResponse
-from utils.lang import MessageTexts
-from utils.config import TELEGRAM_BOT_TOKEN, TELEGRAM_ADMINS_ID
-from utils.log import logger
+from utils import EnvSettings, MessageTexts, logger
bot = Bot(
- token=TELEGRAM_BOT_TOKEN, default=DefaultBotProperties(parse_mode=ParseMode.HTML)
+ token=EnvSettings.TELEGRAM_BOT_TOKEN,
+ default=DefaultBotProperties(parse_mode=ParseMode.HTML),
)
@@ -23,7 +22,7 @@ async def send_message(message: str):
Sends a message to all admins.
"""
try:
- for admin_chatid in TELEGRAM_ADMINS_ID:
+ for admin_chatid in EnvSettings.TELEGRAM_ADMINS_ID:
await bot.send_message(chat_id=admin_chatid, text=message)
except (AiogramError, TelegramAPIError) as e:
logger.error("Failed send report message: %s", str(e))
diff --git a/utils/statedb.py b/utils/statedb.py
index b0bfe66..51f4bf9 100644
--- a/utils/statedb.py
+++ b/utils/statedb.py
@@ -173,6 +173,3 @@ async def clear_and_add_message(
async def close(self) -> None:
await self.engine.dispose()
-
-
-storage = SQLAlchemyStorage()
diff --git a/utils/text_info.py b/utils/text_info.py
index dbfde44..9e23cbc 100644
--- a/utils/text_info.py
+++ b/utils/text_info.py
@@ -5,7 +5,7 @@
from datetime import datetime
from marzban import UserResponse
-from utils.lang import MessageTexts
+from utils import MessageTexts
def user_info(user: UserResponse) -> str: