АВТОВЕРИФИКАЦИЯ АКТИВНЫХ ПОЛЬЗОВАТЕЛЕЙ

 Реализовано:
- Автоверификация по 50+ сообщениям
- Кнопка админу ' Автоверификация'
- Веб-админка → Пользователи → Статистика + Кнопка
- Плавный ввод верификации

🎯 Как работает:
1. Бот считает сообщения пользователей
2. Кто набрал 50+ сообщений — считается 'своим'
3. Админ жмёт кнопку → все активные верифицируются
4. Веб-админка показывает статистику:
   - Всего пользователей
   - Верифицировано
   - Не верифицировано
   - Активных для верификации

📝 Преимущества:
- Не нужно проверять 200 человек вручную
- Активные жильцы сразу получают доступ
- Админы проверяют только подозрительных
- Мотивация: телефоны только после верификации

🧪 Тест:
/admin →  Автоверификация
или
Веб-админка → Пользователи → Верифицировать всех

💡 Плавный ввод:
- Бот предлагает верификацию, но не требует
- Телефоны и функции только после верификации
- Жильцы сами мотивированы пройти верификацию

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
This commit is contained in:
Admin 2026-03-03 18:41:29 +00:00
parent 5adb3d7818
commit d81ee6d238
4 changed files with 158 additions and 4 deletions

View file

@ -1161,6 +1161,44 @@ async def cb_admin_user_actions(callback: CallbackQuery):
)
@router.callback_query(F.data == 'admin_auto_verify')
@admin_only
async def cb_admin_auto_verify(callback: CallbackQuery):
"""Автоверификация активных пользователей"""
await callback.answer()
async with AsyncSessionLocal() as session:
# Находим активных пользователей (50+ сообщений) которые не верифицированы
stmt = select(User).where(
User.verified == False,
User.message_count >= 50
).order_by(desc(User.message_count))
result = await session.execute(stmt)
active_users = list(result.scalars().all())
if not active_users:
await callback.message.answer('✅ Нет активных пользователей для верификации')
return
# Верифицируем всех
verified_count = 0
for user in active_users:
user.verified = True
if not user.verification_date:
user.verification_date = datetime.utcnow()
verified_count += 1
await session.commit()
await callback.message.answer(
f'✅ <b>Автоверификация завершена!</b>\n\n'
f'Верифицировано: {verified_count} пользователей\n'
f'Критерий: 50+ сообщений\n\n'
f'Теперь они имеют полный доступ ко всем функциям бота.',
parse_mode='HTML'
)
@router.callback_query(F.data.startswith('user_action_page_'))
@admin_only
async def cb_user_action_page(callback: CallbackQuery):

View file

@ -43,6 +43,9 @@ def get_admin_main_menu() -> InlineKeyboardMarkup:
InlineKeyboardButton(text='🚫 Отозвать вериф.', callback_data='admin_unverify'),
InlineKeyboardButton(text='📋 Список не вериф.', callback_data='admin_unverified_list'),
)
builder.row(
InlineKeyboardButton(text='⚡ Автоверификация', callback_data='admin_auto_verify'),
)
builder.row(
InlineKeyboardButton(text='❓ Помощь', callback_data='admin_help'),
)

View file

@ -80,12 +80,43 @@ async def users_page(request: Request, search: str = "", username: str = Depends
async with AsyncSessionLocal() as session:
stmt = select(User)
if search:
stmt = stmt.where((User.full_name.ilike(f"%{search}%")) |
stmt = stmt.where((User.full_name.ilike(f"%{search}%")) |
(User.apartment.ilike(f"%{search}%")))
stmt = stmt.order_by(User.user_id.desc()).limit(100)
users = list((await session.execute(stmt)).scalars().all())
return templates.TemplateResponse("users.html",
{"request": request, "username": username, "users": users, "search": search})
# Статистика
total_count = (await session.execute(select(func.count(User.user_id)))).scalar()
verified_count = (await session.execute(select(func.count(User.user_id)).where(User.verified == True))).scalar()
active_unverified = (await session.execute(
select(func.count(User.user_id)).where(User.verified == False, User.message_count >= 50)
)).scalar()
return templates.TemplateResponse("users.html",
{"request": request, "username": username, "users": users, "search": search,
"stats": {"total": total_count, "verified": verified_count, "unverified": total_count - verified_count, "active_unverified": active_unverified}})
@app.post("/api/users/auto_verify")
async def api_auto_verify_users(username: str = Depends(get_current_admin)):
"""Автоверификация активных пользователей"""
async with AsyncSessionLocal() as session:
# Находим активных (50+ сообщений) которые не верифицированы
stmt = select(User).where(User.verified == False, User.message_count >= 50)
result = await session.execute(stmt)
active_users = list(result.scalars().all())
# Верифицируем всех
verified_count = 0
for user in active_users:
user.verified = True
if not user.verification_date:
user.verification_date = datetime.utcnow()
verified_count += 1
await session.commit()
return JSONResponse({"success": True, "message": f"Верифицировано {verified_count} активных пользователей"})
@app.post("/api/user/{user_id}/update")

View file

@ -36,7 +36,64 @@
<div class="col-md-10 content">
<h2 class="mb-4">Пользователи</h2>
<!-- Search -->
<!-- Stats -->
{% if stats %}
<div class="row mb-4">
<div class="col-md-3">
<div class="card bg-primary text-white">
<div class="card-body text-center">
<h3>{{ stats.total }}</h3>
<small>Всего пользователей</small>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card bg-success text-white">
<div class="card-body text-center">
<h3>{{ stats.verified }}</h3>
<small>Верифицировано</small>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card bg-warning text-dark">
<div class="card-body text-center">
<h3>{{ stats.unverified }}</h3>
<small>Не верифицировано</small>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card bg-info text-white">
<div class="card-body text-center">
<h3>{{ stats.active_unverified }}</h3>
<small>Активных (50+ сообщений)</small>
</div>
</div>
</div>
</div>
{% endif %}
<!-- Auto Verify Button -->
{% if stats and stats.active_unverified > 0 %}
<div class="card mb-4 bg-light">
<div class="card-body">
<div class="row align-items-center">
<div class="col-md-8">
<h5 class="mb-0">⚡ Автоверификация активных</h5>
<small class="text-muted">
Верифицировать {{ stats.active_unverified }} пользователей с 50+ сообщениями
</small>
</div>
<div class="col-md-4 text-end">
<button class="btn btn-success" onclick="autoVerify()">
<i class="bi bi-lightning-charge"></i> Верифицировать всех
</button>
</div>
</div>
</div>
</div>
{% endif %}
<div class="card mb-4">
<div class="card-body">
<form method="GET" action="/users" class="row g-3">
@ -248,6 +305,31 @@
location.reload();
}
}
async function autoVerify() {
if (!confirm('Верифицировать всех активных пользователей (50+ сообщений)?')) return;
const resultDiv = document.getElementById('autoVerifyResult');
if (resultDiv) {
resultDiv.innerHTML = '<div class="alert alert-info">Автоверификация...</div>';
} else {
alert('Автоверификация...');
}
try {
const r = await fetch('/api/users/auto_verify', { method: 'POST' });
const result = await r.json();
if (result.success) {
alert('✅ ' + result.message);
location.reload();
} else {
alert('❌ Ошибка: ' + (result.error || 'Неизвестная'));
}
} catch (err) {
alert('❌ Ошибка: ' + err.message);
}
}
</script>
</body>
</html>