@@ -58,7 +58,7 @@ async def handle_admin_message(message: types.Message, state: FSMContext):
|
||||
)
|
||||
)
|
||||
builder.row(
|
||||
InlineKeyboardButton(text="📢 Массовая рассылка", callback_data="send_to_alls")
|
||||
InlineKeyboardButton(text="📢 Массовая рассылка", callback_data="send_to")
|
||||
)
|
||||
builder.row(
|
||||
InlineKeyboardButton(
|
||||
@@ -261,14 +261,40 @@ async def export_payments_csv(callback_query: CallbackQuery, session: Any):
|
||||
)
|
||||
|
||||
|
||||
@router.callback_query(F.data == "send_to_alls", IsAdminFilter())
|
||||
@router.callback_query(F.data == "send_to", IsAdminFilter())
|
||||
async def handle_send_to_all(callback_query: CallbackQuery, state: FSMContext):
|
||||
builder = InlineKeyboardBuilder()
|
||||
builder.row(InlineKeyboardButton(text="📢 Отправить всем", callback_data="send_to_all"))
|
||||
builder.row(InlineKeyboardButton(text="📢 Отправить с подпиской", callback_data="send_to_subscribed"))
|
||||
builder.row(InlineKeyboardButton(text="📢 Отправить без подписки", callback_data="send_to_unsubscribed"))
|
||||
builder.row(InlineKeyboardButton(text="🔙 Назад", callback_data="admin"))
|
||||
await callback_query.message.answer(
|
||||
"✍️ Введите текст сообщения, который вы хотите отправить всем клиентам 📢🌐:",
|
||||
"✍️ Выберите группу пользователей и введите текст сообщения для рассылки:",
|
||||
reply_markup=builder.as_markup(),
|
||||
)
|
||||
|
||||
@router.callback_query(F.data == "send_to_all", IsAdminFilter())
|
||||
async def handle_send_to_all(callback_query: CallbackQuery, state: FSMContext):
|
||||
await state.update_data(send_to="all")
|
||||
await callback_query.message.answer(
|
||||
"✍️ Введите текст сообщения для рассылки всем пользователям:"
|
||||
)
|
||||
await state.set_state(UserEditorState.waiting_for_message)
|
||||
|
||||
@router.callback_query(F.data == "send_to_subscribed", IsAdminFilter())
|
||||
async def handle_send_to_subscribed(callback_query: CallbackQuery, state: FSMContext):
|
||||
await state.update_data(send_to="subscribed")
|
||||
await callback_query.message.answer(
|
||||
"✍️ Введите текст сообщения для рассылки пользователям с активной подпиской:"
|
||||
)
|
||||
await state.set_state(UserEditorState.waiting_for_message)
|
||||
|
||||
@router.callback_query(F.data == "send_to_unsubscribed", IsAdminFilter())
|
||||
async def handle_send_to_unsubscribed(callback_query: CallbackQuery, state: FSMContext):
|
||||
await state.update_data(send_to="unsubscribed")
|
||||
await callback_query.message.answer(
|
||||
"✍️ Введите текст сообщения для рассылки пользователям без активной подписки:"
|
||||
)
|
||||
await state.set_state(UserEditorState.waiting_for_message)
|
||||
|
||||
|
||||
@@ -279,7 +305,26 @@ async def process_message_to_all(
|
||||
text_message = message.text
|
||||
|
||||
try:
|
||||
tg_ids = await session.fetch("SELECT tg_id FROM connections")
|
||||
state_data = await state.get_data()
|
||||
send_to = state_data.get('send_to', 'all')
|
||||
|
||||
if send_to == 'all':
|
||||
tg_ids = await session.fetch("SELECT DISTINCT c.tg_id FROM connections c")
|
||||
elif send_to == 'subscribed':
|
||||
tg_ids = await session.fetch("""
|
||||
SELECT DISTINCT c.tg_id
|
||||
FROM connections c
|
||||
JOIN keys k ON c.tg_id = k.tg_id
|
||||
WHERE k.expiry_time > CURRENT_TIMESTAMP
|
||||
""")
|
||||
elif send_to == 'unsubscribed':
|
||||
tg_ids = await session.fetch("""
|
||||
SELECT c.tg_id
|
||||
FROM connections c
|
||||
LEFT JOIN keys k ON c.tg_id = k.tg_id
|
||||
GROUP BY c.tg_id
|
||||
HAVING COUNT(k.tg_id) = 0 OR MAX(k.expiry_time) <= CURRENT_TIMESTAMP
|
||||
""")
|
||||
|
||||
total_users = len(tg_ids)
|
||||
success_count = 0
|
||||
|
||||
@@ -115,6 +115,7 @@ async def handle_username_input(
|
||||
)
|
||||
)
|
||||
builder.row(InlineKeyboardButton(text="❌ Удалить клиента", callback_data=f"confirm_delete_user_{tg_id}"))
|
||||
builder.row(InlineKeyboardButton(text="🔄 Обновить клиента", callback_data=f"user_info|{tg_id}"))
|
||||
builder.row(
|
||||
InlineKeyboardButton(
|
||||
text="✉️ Отправить сообщение",
|
||||
@@ -202,6 +203,7 @@ async def handle_tg_id_input(message: types.Message, state: FSMContext, session:
|
||||
)
|
||||
)
|
||||
builder.row(InlineKeyboardButton(text="❌ Удалить клиента", callback_data=f"confirm_delete_user_{tg_id}"))
|
||||
builder.row(InlineKeyboardButton(text="🔄 Обновить клиента", callback_data=f"user_info|{tg_id}"))
|
||||
builder.row(
|
||||
InlineKeyboardButton(
|
||||
text="🔄 Восстановить пробник",
|
||||
@@ -647,6 +649,13 @@ async def handle_user_info(
|
||||
builder.row(InlineKeyboardButton(text="📝 Изменить баланс", callback_data=f"change_balance_{tg_id}"))
|
||||
builder.row(InlineKeyboardButton(text="🔄 Восстановить пробник", callback_data=f"restore_trial_{tg_id}"))
|
||||
builder.row(InlineKeyboardButton(text="❌ Удалить клиента", callback_data=f"confirm_delete_user_{tg_id}"))
|
||||
builder.row(InlineKeyboardButton(text="🔄 Обновить клиента", callback_data=f"user_info|{tg_id}"))
|
||||
builder.row(
|
||||
InlineKeyboardButton(
|
||||
text="✉️ Отправить сообщение",
|
||||
callback_data=f"send_message_{tg_id}"
|
||||
)
|
||||
)
|
||||
builder.row(InlineKeyboardButton(text="🔙 Назад", callback_data="user_editor"))
|
||||
|
||||
user_info = (
|
||||
|
||||
@@ -190,6 +190,13 @@ async def process_callback_view_key(callback_query: types.CallbackQuery, session
|
||||
|
||||
builder = InlineKeyboardBuilder()
|
||||
|
||||
builder.row(
|
||||
InlineKeyboardButton(
|
||||
text="🔄 Обновить подписку",
|
||||
callback_data=f"update_subscription|{key_name}",
|
||||
)
|
||||
)
|
||||
|
||||
builder.row(
|
||||
InlineKeyboardButton(text="🍏 Скачать для iOS", url=DOWNLOAD_IOS),
|
||||
InlineKeyboardButton(
|
||||
@@ -222,15 +229,7 @@ async def process_callback_view_key(callback_query: types.CallbackQuery, session
|
||||
InlineKeyboardButton(
|
||||
text="❌ Удалить", callback_data=f"delete_key|{key_name}"
|
||||
),
|
||||
)
|
||||
|
||||
if not key.startswith(PUBLIC_LINK):
|
||||
builder.row(
|
||||
InlineKeyboardButton(
|
||||
text="🔄 Обновить подписку",
|
||||
callback_data=f"update_subscription|{key_name}",
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
builder.row(
|
||||
InlineKeyboardButton(text="👤 Личный кабинет", callback_data="profile")
|
||||
|
||||
@@ -413,3 +413,29 @@ async def check_online_users():
|
||||
logger.error(
|
||||
f"Не удалось проверить пользователей на сервере {server_id}: {e}"
|
||||
)
|
||||
|
||||
|
||||
async def update_all_keys():
|
||||
try:
|
||||
conn = await asyncpg.connect(DATABASE_URL)
|
||||
keys = await conn.fetch("SELECT tg_id, client_id, email, expiry_time, server_id FROM keys")
|
||||
|
||||
for key in keys:
|
||||
tg_id = key['tg_id']
|
||||
client_id = key['client_id']
|
||||
email = key['email']
|
||||
expiry_time = key['expiry_time']
|
||||
cluster_id = key['server_id']
|
||||
|
||||
try:
|
||||
await update_key_on_cluster(tg_id, client_id, email, expiry_time, cluster_id)
|
||||
await store_key(tg_id, client_id, email, expiry_time, key['key'], cluster_id, conn)
|
||||
logger.info(f"Ключ {client_id} успешно обновлен и сохранен")
|
||||
except Exception as e:
|
||||
logger.error(f"Ошибка при обновлении и сохранении ключа {client_id}: {e}")
|
||||
|
||||
logger.info("Все ключи успешно обновлены и сохранены")
|
||||
except Exception as e:
|
||||
logger.error(f"Ошибка при обновлении всех ключей: {e}")
|
||||
finally:
|
||||
await conn.close()
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import random
|
||||
import re
|
||||
import json
|
||||
|
||||
import aiohttp
|
||||
import asyncpg
|
||||
|
||||
from bot import bot
|
||||
@@ -9,6 +11,21 @@ from database import get_servers_from_db
|
||||
from logger import logger
|
||||
|
||||
|
||||
async def get_usd_rate():
|
||||
try:
|
||||
async with aiohttp.ClientSession() as session:
|
||||
async with session.get('https://www.cbr-xml-daily.ru/daily_json.js') as response:
|
||||
if response.status == 200:
|
||||
data = await response.text()
|
||||
usd = float(json.loads(data)['Valute']['USD']['Value'])
|
||||
else:
|
||||
usd = float(100) # Default value if request fails
|
||||
except Exception as e:
|
||||
logger.exception(f"Error fetching USD rate: {e}")
|
||||
usd = float(100) # Default value if an exception occurs
|
||||
return usd
|
||||
|
||||
|
||||
def sanitize_key_name(key_name: str) -> str:
|
||||
"""
|
||||
Очищает название ключа, оставляя только допустимые символы.
|
||||
|
||||
Reference in New Issue
Block a user