support invite links/ shadow bans/ bulk preemptive bans

This commit is contained in:
Vladless
2025-07-25 05:40:45 +03:00
parent a90c607dab
commit cad9c50c80
7 changed files with 285 additions and 14 deletions
+106 -7
View File
@@ -66,6 +66,7 @@ from .keyboard import (
build_users_balance_kb,
build_users_key_expiry_kb,
build_users_key_show_kb,
build_user_ban_type_kb
)
@@ -94,6 +95,7 @@ class RenewTariffState(StatesGroup):
class BanUserStates(StatesGroup):
waiting_for_reason = State()
waiting_for_ban_duration = State()
waiting_for_forever_reason = State()
@router.callback_query(AdminUserEditorCallback.filter(F.action == "users_hwid_menu"), IsAdminFilter())
@@ -1567,6 +1569,73 @@ async def handle_reset_traffic(
@router.callback_query(AdminUserEditorCallback.filter(F.action == "users_ban"), IsAdminFilter())
async def handle_user_ban(callback: CallbackQuery, callback_data: AdminUserEditorCallback, state: FSMContext):
await state.clear()
await state.update_data(tg_id=callback_data.tg_id)
await callback.message.edit_text(
text="🚫 Выберите тип блокировки пользователя:",
reply_markup=build_user_ban_type_kb(callback_data.tg_id),
)
@router.callback_query(AdminUserEditorCallback.filter(F.action == "users_ban_forever"), IsAdminFilter())
async def handle_ban_forever_start(callback: CallbackQuery, callback_data: AdminUserEditorCallback, state: FSMContext):
await state.set_state(BanUserStates.waiting_for_forever_reason)
await state.update_data(tg_id=callback_data.tg_id)
kb = InlineKeyboardBuilder()
kb.row(build_editor_btn("⬅️ Назад", tg_id=callback_data.tg_id, edit=True))
await callback.message.edit_text(
text="✏️ Введите причину <b>постоянной блокировки</b> (или <code>-</code>, чтобы пропустить):",
reply_markup=kb.as_markup(),
)
@router.message(BanUserStates.waiting_for_forever_reason, IsAdminFilter())
async def handle_ban_forever_reason_input(message: Message, state: FSMContext, session: AsyncSession):
reason = message.text.strip()
if reason == "-":
reason = None
user_data = await state.get_data()
tg_id = user_data.get("tg_id")
stmt = (
pg_insert(ManualBan)
.values(
tg_id=tg_id,
reason=reason,
banned_by=message.from_user.id,
until=None,
banned_at=datetime.now(timezone.utc),
)
.on_conflict_do_update(
index_elements=[ManualBan.tg_id],
set_={
"reason": reason,
"until": None,
"banned_by": message.from_user.id,
"banned_at": datetime.now(timezone.utc),
},
)
)
await session.execute(stmt)
await session.commit()
await state.clear()
await message.answer(
text=(
f"✅ Пользователь <code>{tg_id}</code> забанен навсегда."
f"{f'\n📄 Причина: {reason}' if reason else ''}"
),
reply_markup=build_editor_kb(tg_id, edit=True),
)
@router.callback_query(AdminUserEditorCallback.filter(F.action == "users_ban_temporary"), IsAdminFilter())
async def handle_ban_temporary(callback: CallbackQuery, callback_data: AdminUserEditorCallback, state: FSMContext):
await state.set_state(BanUserStates.waiting_for_reason)
await state.update_data(tg_id=callback_data.tg_id)
@@ -1574,7 +1643,7 @@ async def handle_user_ban(callback: CallbackQuery, callback_data: AdminUserEdito
kb.row(build_editor_btn("⬅️ Назад", tg_id=callback_data.tg_id, edit=True))
await callback.message.edit_text(
text="✏️ Введите причину блокировки (или <code>-</code>, чтобы пропустить):",
text="✏️ Введите причину <b>временной блокировки</b> (или <code>-</code>, чтобы пропустить):",
reply_markup=kb.as_markup(),
)
@@ -1606,10 +1675,11 @@ async def handle_ban_duration_input(message: Message, state: FSMContext, session
try:
days = int(message.text.strip())
if days < 1:
await message.answer("❗ Укажите срок минимум в 1 день.")
return
until = None
if days > 0:
until = datetime.now(timezone.utc) + timedelta(days=days)
until = datetime.now(timezone.utc) + timedelta(days=days)
stmt = (
pg_insert(ManualBan)
@@ -1635,9 +1705,8 @@ async def handle_ban_duration_input(message: Message, state: FSMContext, session
await session.commit()
text = (
f"✅ Пользователь <code>{tg_id}</code> забанен "
f"{'навсегда' if not until else f'до {until:%Y-%m-%d %H:%M}'}."
" Нажмите кнопку ниже для возврата в профиль."
f"✅ Пользователь <code>{tg_id}</code> временно забанен до <b>{until:%Y-%m-%d %H:%M}</b> по UTC."
f"{f'\n📄 Причина: {reason}' if reason else ''}"
)
await message.answer(text=text, reply_markup=build_editor_kb(tg_id, edit=True))
@@ -1648,6 +1717,36 @@ async def handle_ban_duration_input(message: Message, state: FSMContext, session
await state.clear()
@router.callback_query(AdminUserEditorCallback.filter(F.action == "users_ban_shadow"), IsAdminFilter())
async def handle_ban_shadow(callback: CallbackQuery, callback_data: AdminUserEditorCallback, session: AsyncSession):
stmt = (
pg_insert(ManualBan)
.values(
tg_id=callback_data.tg_id,
reason="shadow",
banned_by=callback.from_user.id,
until=None,
banned_at=datetime.now(timezone.utc),
)
.on_conflict_do_update(
index_elements=[ManualBan.tg_id],
set_={
"reason": "shadow",
"until": None,
"banned_by": callback.from_user.id,
"banned_at": datetime.now(timezone.utc),
},
)
)
await session.execute(stmt)
await session.commit()
await callback.message.edit_text(
text=f"👻 Пользователь <code>{callback_data.tg_id}</code> получил теневой бан.",
reply_markup=build_editor_kb(callback_data.tg_id, edit=True),
)
@router.callback_query(AdminUserEditorCallback.filter(F.action == "users_unban"), IsAdminFilter())
async def handle_user_unban(
callback: CallbackQuery,