domovoy_bot/handlers/phones.py
Admin ba4676b0af v1.0 MVP - Инициализация проекта 🏠
 Регистрация и верификация жильцов
 Рейтинг активности (уровни)
 Детект шпионов (Score 0-100)
 Анти-мат система (3 предупреждения → бан)
 Админ-панель с рассылкой
 Учёт квартир (несколько жильцов)
 Телефоны экстренных служб и мастеров
 Еженедельный экспорт JSON
 Прокси (socks5) для обхода РКН

Бекап: backups/versions/v1.0_mvp_2026-02-26/

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-02-27 10:54:16 +00:00

297 lines
10 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
Управление телефонами пользователей
"""
import logging
import re
from aiogram import Router, F
from aiogram.types import Message
from aiogram.filters import Command
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select
from database.db import AsyncSessionLocal
from database.models import User
from utils.decorators import admin_only
from utils.validators import validate_phone, normalize_phone
logger = logging.getLogger(__name__)
router = Router()
def format_phone_display(phone: str) -> str:
"""Форматирование телефона для отображения"""
if not phone:
return 'не указан'
# Добавляем кликабельную ссылку tel:
cleaned = re.sub(r'[^\d+]', '', phone)
return f'<a href="tel:{cleaned}">{phone}</a>'
@router.message(Command('add_phone'))
@admin_only
async def cmd_add_phone(message: Message):
"""
Добавить телефон пользователю
Использование: /add_phone <user_id> <телефон>
"""
args = message.text.split(maxsplit=2)
if len(args) < 3:
await message.answer(
'Использование: <code>/add_phone &lt;user_id&gt; &lt;телефон&gt;</code>\n\n'
'Пример: <code>/add_phone 123456789 +7 (999) 123-45-67</code>',
parse_mode='HTML'
)
return
try:
user_id = int(args[1])
except ValueError:
await message.answer('❌ Неверный ID пользователя')
return
phone = args[2].strip()
if not validate_phone(phone):
await message.answer('❌ Неверный формат телефона\n\nПример: +7 (999) 123-45-67')
return
# Нормализуем телефон
phone = normalize_phone(phone)
async with AsyncSessionLocal() as session:
# Находим пользователя
stmt = select(User).where(User.user_id == user_id)
result = await session.execute(stmt)
user = result.scalar_one_or_none()
if not user:
await message.answer('❌ Пользователь не найден')
return
# Добавляем телефон
user.phone = phone
await session.commit()
logger.info(f'Добавлен телефон пользователю {user_id}: {phone}')
await message.answer(
f'✅ <b>Телефон добавлен</b>\n\n'
f'Пользователь: {user.full_name}\n'
f'ID: <code>{user_id}</code>\n'
f'Телефон: <code>{phone}</code>\n\n'
f'💡 Теперь можно позвонить кликом!',
parse_mode='HTML'
)
@router.message(Command('edit_phone'))
@admin_only
async def cmd_edit_phone(message: Message):
"""
Изменить телефон пользователю
Использование: /edit_phone <user_id> <телефон>
"""
args = message.text.split(maxsplit=2)
if len(args) < 3:
await message.answer(
'Использование: <code>/edit_phone &lt;user_id&gt; &lt;телефон&gt;</code>\n\n'
'Пример: <code>/edit_phone 123456789 +7 (999) 999-99-99</code>',
parse_mode='HTML'
)
return
try:
user_id = int(args[1])
except ValueError:
await message.answer('❌ Неверный ID пользователя')
return
phone = args[2].strip()
if not validate_phone(phone):
await message.answer('❌ Неверный формат телефона')
return
phone = normalize_phone(phone)
async with AsyncSessionLocal() as session:
stmt = select(User).where(User.user_id == user_id)
result = await session.execute(stmt)
user = result.scalar_one_or_none()
if not user:
await message.answer('❌ Пользователь не найден')
return
old_phone = user.phone
user.phone = phone
await session.commit()
logger.info(f'Изменён телефон пользователю {user_id}: {old_phone}{phone}')
await message.answer(
f'✅ <b>Телефон изменён</b>\n\n'
f'Пользователь: {user.full_name}\n'
f'ID: <code>{user_id}</code>\n'
f'Было: <code>{old_phone or "не указан"}</code>\n'
f'Стало: <code>{phone}</code>',
parse_mode='HTML'
)
@router.message(Command('remove_phone'))
@router.message(Command('del_phone'))
@admin_only
async def cmd_remove_phone(message: Message):
"""
Удалить телефон у пользователя
Использование: /remove_phone <user_id>
"""
args = message.text.split()
if len(args) < 2:
await message.answer(
'Использование: <code>/remove_phone &lt;user_id&gt;</code>\n\n'
'Пример: <code>/remove_phone 123456789</code>',
parse_mode='HTML'
)
return
try:
user_id = int(args[1])
except ValueError:
await message.answer('❌ Неверный ID пользователя')
return
async with AsyncSessionLocal() as session:
stmt = select(User).where(User.user_id == user_id)
result = await session.execute(stmt)
user = result.scalar_one_or_none()
if not user:
await message.answer('❌ Пользователь не найден')
return
old_phone = user.phone
user.phone = None
await session.commit()
logger.info(f'Удалён телефон пользователю {user_id}: {old_phone}')
await message.answer(
f'✅ <b>Телефон удалён</b>\n\n'
f'Пользователь: {user.full_name}\n'
f'ID: <code>{user_id}</code>\n'
f'Был: <code>{old_phone or "не указан"}</code>',
parse_mode='HTML'
)
@router.message(Command('myphone'))
async def cmd_myphone(message: Message):
"""
Добавить/изменить свой телефон (для жильцов)
Использование: /myphone +7 (999) 123-45-67
"""
args = message.text.split(maxsplit=1)
if len(args) < 2:
# Показываем текущий телефон
async with AsyncSessionLocal() as session:
stmt = select(User).where(User.user_id == message.from_user.id)
result = await session.execute(stmt)
user = result.scalar_one_or_none()
if user and user.phone:
await message.answer(
f'📱 <b>Ваш телефон</b>\n\n'
f'<code>{user.phone}</code>\n\n'
f'Чтобы изменить: <code>/myphone +7 (999) 123-45-67</code>',
parse_mode='HTML'
)
else:
await message.answer(
'📱 <b>Ваш телефон не указан</b>\n\n'
'Добавьте телефон командой:\n'
'<code>/myphone +7 (999) 123-45-67</code>\n\n'
'Это поможет соседям связаться с вами!',
parse_mode='HTML'
)
return
phone = args[1].strip()
if not validate_phone(phone):
await message.answer('❌ Неверный формат телефона\n\nПример: +7 (999) 123-45-67')
return
phone = normalize_phone(phone)
async with AsyncSessionLocal() as session:
stmt = select(User).where(User.user_id == message.from_user.id)
result = await session.execute(stmt)
user = result.scalar_one_or_none()
if not user:
await message.answer('❌ Вы не зарегистрированы. Нажмите /start')
return
old_phone = user.phone
user.phone = phone
await session.commit()
logger.info(f'Пользователь {message.from_user.id} установил телефон: {phone}')
await message.answer(
f'✅ <b>Телефон сохранён</b>\n\n'
f'<code>{phone}</code>\n\n'
f'Теперь соседи могут связаться с вами!',
parse_mode='HTML'
)
@router.message(Command('phone'))
@admin_only
async def cmd_phone_info(message: Message):
"""
Показать телефон пользователя
Использование: /phone <user_id>
"""
args = message.text.split()
if len(args) < 2:
await message.answer(
'Использование: <code>/phone &lt;user_id&gt;</code>\n\n'
'Пример: <code>/phone 123456789</code>',
parse_mode='HTML'
)
return
try:
user_id = int(args[1])
except ValueError:
await message.answer('❌ Неверный ID пользователя')
return
async with AsyncSessionLocal() as session:
stmt = select(User).where(User.user_id == user_id)
result = await session.execute(stmt)
user = result.scalar_one_or_none()
if not user:
await message.answer('❌ Пользователь не найден')
return
phone_text = format_phone_display(user.phone)
await message.answer(
f'📱 <b>Телефон</b>\n\n'
f'Пользователь: {user.full_name}\n'
f'Квартира: {user.apartment or "не указана"}\n'
f'Телефон: {phone_text}\n\n'
f'💡 Нажмите на номер чтобы позвонить!',
parse_mode='HTML'
)