add format day in csv/maintenance mode

This commit is contained in:
Vladless
2025-04-26 11:14:13 +03:00
parent 22121b9171
commit 18d3b4246a
5 changed files with 46 additions and 16 deletions
+5
View File
@@ -1,6 +1,8 @@
from aiogram.types import InlineKeyboardMarkup
from aiogram.utils.keyboard import InlineKeyboardBuilder
from middlewares import maintenance
from ..panel.keyboard import AdminPanelCallback, build_admin_back_btn
@@ -11,6 +13,9 @@ def build_management_kb() -> InlineKeyboardMarkup:
builder.button(text="🔄 Перезагрузить бота", callback_data=AdminPanelCallback(action="restart").pack())
builder.button(text="🌐 Сменить домен", callback_data=AdminPanelCallback(action="change_domain").pack())
builder.button(text="🔑 Восстановить пробники", callback_data=AdminPanelCallback(action="restore_trials").pack())
maintenance_text = "🛠️ Выключить тех. работы" if maintenance.maintenance_mode else "🛠️ Включить тех. работы"
builder.button(text=maintenance_text, callback_data=AdminPanelCallback(action="toggle_maintenance").pack())
builder.row(build_admin_back_btn())
builder.adjust(1)
return builder.as_markup()
@@ -9,6 +9,7 @@ from logger import logger
from ..panel.keyboard import build_admin_back_kb
from .keyboard import AdminPanelCallback, build_management_kb
from middlewares import maintenance
router = Router()
@@ -73,3 +74,14 @@ async def process_new_domain(message: Message, state: FSMContext, session: Conne
await message.answer(f"✅ Домен успешно изменен на {new_domain}!", reply_markup=build_admin_back_kb("admin"))
await state.clear()
@router.callback_query(AdminPanelCallback.filter(F.action == "toggle_maintenance"))
async def toggle_maintenance_mode(callback: CallbackQuery):
maintenance.maintenance_mode = not maintenance.maintenance_mode
new_status = "включён" if maintenance.maintenance_mode else "выключен"
await callback.answer(f"🛠️ Режим обслуживания {new_status}.", show_alert=True)
await callback.message.edit_reply_markup(reply_markup=build_management_kb())
+3 -14
View File
@@ -8,6 +8,8 @@ from .loggings import LoggingMiddleware
from .session import SessionMiddleware
from .throttling import ThrottlingMiddleware
from .user import UserMiddleware
from .maintenance import MaintenanceModeMiddleware
def register_middleware(
@@ -16,40 +18,27 @@ def register_middleware(
exclude: Iterable[str] | None = None,
) -> None:
"""Регистрирует middleware в диспетчере.
Args:
dispatcher: Экземпляр диспетчера Aiogram
middlewares: Опциональный список middleware для регистрации.
Если не указан, регистрируются все стандартные middleware.
exclude: Опциональный список имен middleware, которые нужно исключить из регистрации.
Применяется только если middlewares не указан.
"""
# Если middleware не указаны, используем стандартный набор
if middlewares is None:
# Словарь всех доступных middleware
available_middlewares = {
"admin": AdminMiddleware(),
"session": SessionMiddleware(),
"maintenance": MaintenanceModeMiddleware(),
"logging": LoggingMiddleware(),
"throttling": ThrottlingMiddleware(),
"user": UserMiddleware(),
}
# Фильтруем middleware по списку исключений
exclude_set = set(exclude or [])
middlewares = [middleware for name, middleware in available_middlewares.items() if name not in exclude_set]
# Регистрируем middleware для всех типов обработчиков
handlers = [
dispatcher.message,
dispatcher.callback_query,
dispatcher.inline_query,
# Можно добавить другие типы обработчиков при необходимости
]
# Регистрируем каждый middleware для каждого типа обработчика
for middleware in middlewares:
# Если передан класс, а не экземпляр, создаем экземпляр
if isinstance(middleware, type):
middleware = middleware()
+20
View File
@@ -0,0 +1,20 @@
from aiogram import BaseMiddleware
from aiogram.types import Message, CallbackQuery
from config import ADMIN_ID
maintenance_mode = False
class MaintenanceModeMiddleware(BaseMiddleware):
async def __call__(self, handler, event, data):
if maintenance_mode:
user_id = None
if isinstance(event, Message):
user_id = event.from_user.id
elif isinstance(event, CallbackQuery):
user_id = event.from_user.id
if user_id and user_id not in ADMIN_ID:
await event.answer("⚙️ Бот временно недоступен. Ведутся технические работы.")
return
return await handler(event, data)
+6 -2
View File
@@ -1,4 +1,5 @@
import csv
from datetime import datetime
from io import StringIO
from typing import Any
@@ -172,7 +173,7 @@ async def export_hot_leads_csv(session: Any) -> BufferedInputFile:
async def export_keys_csv(session) -> BufferedInputFile:
"""
Экспорт подписок в CSV.
Экспорт подписок в CSV с нормальными датами.
"""
keys = await session.fetch("""
SELECT tg_id, client_id, email, created_at, expiry_time, key, server_id, is_frozen, alias
@@ -184,9 +185,12 @@ async def export_keys_csv(session) -> BufferedInputFile:
buffer.write("tg_id,client_id,email,created_at,expiry_time,key,server_id,is_frozen,alias\n")
for row in keys:
created_at = datetime.utcfromtimestamp(row['created_at'] / 1000).strftime("%Y-%m-%d %H:%M:%S")
expiry_time = datetime.utcfromtimestamp(row['expiry_time'] / 1000).strftime("%Y-%m-%d %H:%M:%S")
buffer.write(
f"{row['tg_id']},{row['client_id']},{row['email']},"
f"{row['created_at']},{row['expiry_time']},{row['key']},"
f"{created_at},{expiry_time},{row['key']},"
f"{row['server_id']},{row['is_frozen']},{row['alias'] or ''}\n"
)