Merge pull request #127 from izzzzzi/main

Backlog
This commit is contained in:
Vladislav Lisitsyn
2025-01-06 02:57:04 +03:00
committed by GitHub
5 changed files with 109 additions and 13 deletions
+49 -4
View File
@@ -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
+9
View File
@@ -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 = (
+8 -9
View File
@@ -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")
+26
View File
@@ -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()
+17
View File
@@ -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:
"""
Очищает название ключа, оставляя только допустимые символы.