✅ Реализовано: - Автоверификация по 50+ сообщениям - Кнопка админу '⚡ Автоверификация' - Веб-админка → Пользователи → Статистика + Кнопка - Плавный ввод верификации 🎯 Как работает: 1. Бот считает сообщения пользователей 2. Кто набрал 50+ сообщений — считается 'своим' 3. Админ жмёт кнопку → все активные верифицируются 4. Веб-админка показывает статистику: - Всего пользователей - Верифицировано - Не верифицировано - Активных для верификации 📝 Преимущества: - Не нужно проверять 200 человек вручную - Активные жильцы сразу получают доступ - Админы проверяют только подозрительных - Мотивация: телефоны только после верификации 🧪 Тест: /admin → ⚡ Автоверификация или Веб-админка → Пользователи → Верифицировать всех 💡 Плавный ввод: - Бот предлагает верификацию, но не требует - Телефоны и функции только после верификации - Жильцы сами мотивированы пройти верификацию Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
581 lines
24 KiB
Python
581 lines
24 KiB
Python
"""
|
||
Web Admin Interface v3.0 - MEGA ADMIN PANEL
|
||
Полноценное управление ВСЕМ функционалом бота
|
||
"""
|
||
import logging
|
||
import json
|
||
import aiohttp
|
||
from fastapi import FastAPI, Request, Depends, HTTPException, status, Form, File, UploadFile
|
||
from fastapi.security import HTTPBasic, HTTPBasicCredentials
|
||
from fastapi.staticfiles import StaticFiles
|
||
from fastapi.templating import Jinja2Templates
|
||
from fastapi.responses import HTMLResponse, JSONResponse, RedirectResponse
|
||
from sqlalchemy.ext.asyncio import AsyncSession
|
||
from sqlalchemy import select, func, update, delete, desc
|
||
from datetime import datetime, timedelta
|
||
import secrets
|
||
import config
|
||
|
||
from database.db import AsyncSessionLocal
|
||
from database.models import (
|
||
User, Message, Poll, Ad, PaymentReminder, Schedule,
|
||
VerificationRequest, Service, Announcement, Event
|
||
)
|
||
|
||
logger = logging.getLogger(__name__)
|
||
|
||
app = FastAPI(title="Домовой Бот - MEGA Admin Panel", version="3.0.0")
|
||
templates = Jinja2Templates(directory="web/templates")
|
||
app.mount("/static", StaticFiles(directory="web/static"), name="static")
|
||
app.mount("/static/service_images", StaticFiles(directory="data/service_images"), name="service_images")
|
||
security = HTTPBasic()
|
||
|
||
|
||
def get_current_admin(credentials: HTTPBasicCredentials = Depends(security)):
|
||
"""Проверка админа"""
|
||
correct_username = secrets.compare_digest(credentials.username, config.WEB_ADMIN_LOGIN)
|
||
correct_password = secrets.compare_digest(credentials.password, config.WEB_ADMIN_PASSWORD)
|
||
if not (correct_username and correct_password):
|
||
raise HTTPException(status_code=401, detail="Неверный логин или пароль",
|
||
headers={"WWW-Authenticate": "Basic"})
|
||
return credentials.username
|
||
|
||
|
||
# ============================================================================
|
||
# ГЛАВНАЯ
|
||
# ============================================================================
|
||
|
||
@app.get("/", response_class=HTMLResponse)
|
||
async def dashboard(request: Request, username: str = Depends(get_current_admin)):
|
||
"""Дашборд"""
|
||
async with AsyncSessionLocal() as session:
|
||
users_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()
|
||
messages_count = (await session.execute(select(func.count(Message.id)))).scalar()
|
||
active_ads = (await session.execute(
|
||
select(func.count(Ad.ad_id)).where(Ad.is_active == True))).scalar()
|
||
active_polls = (await session.execute(
|
||
select(func.count(Poll.poll_id)).where(Poll.is_active == True))).scalar()
|
||
upcoming_events = (await session.execute(
|
||
select(func.count(Event.id)).where(Event.is_active == True))).scalar()
|
||
|
||
return templates.TemplateResponse("dashboard.html", {
|
||
"request": request, "username": username,
|
||
"stats": {
|
||
"users": users_count, "verified": verified_count,
|
||
"messages": messages_count, "ads": active_ads,
|
||
"polls": active_polls, "events": upcoming_events
|
||
}
|
||
})
|
||
|
||
|
||
# ============================================================================
|
||
# ПОЛЬЗОВАТЕЛИ
|
||
# ============================================================================
|
||
|
||
@app.get("/users", response_class=HTMLResponse)
|
||
async def users_page(request: Request, search: str = "", username: str = Depends(get_current_admin)):
|
||
"""Пользователи"""
|
||
async with AsyncSessionLocal() as session:
|
||
stmt = select(User)
|
||
if 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())
|
||
|
||
# Статистика
|
||
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")
|
||
async def api_update_user(user_id: int, request: Request,
|
||
username: str = Depends(get_current_admin)):
|
||
"""Обновить пользователя"""
|
||
data = await request.json()
|
||
async with AsyncSessionLocal() as session:
|
||
update_data = {}
|
||
if 'apartment' in data: update_data['apartment'] = data['apartment'].upper()
|
||
if 'phone' in data: update_data['phone'] = data['phone']
|
||
if 'verified' in data:
|
||
update_data['verified'] = bool(data['verified'])
|
||
if data['verified']: update_data['verification_date'] = datetime.utcnow()
|
||
if 'banned' in data: update_data['is_banned'] = bool(data['banned'])
|
||
if 'rating' in data: update_data['rating'] = int(data['rating'])
|
||
if update_data:
|
||
await session.execute(update(User).where(User.user_id == user_id).values(**update_data))
|
||
await session.commit()
|
||
return JSONResponse({"success": True})
|
||
|
||
|
||
@app.post("/api/user/{user_id}/ban")
|
||
async def api_ban_user(user_id: int, username: str = Depends(get_current_admin)):
|
||
"""Забанить"""
|
||
async with AsyncSessionLocal() as session:
|
||
await session.execute(update(User).where(User.user_id == user_id).values(is_banned=True))
|
||
await session.commit()
|
||
return JSONResponse({"success": True, "message": "Забанен"})
|
||
|
||
|
||
@app.post("/api/user/{user_id}/unban")
|
||
async def api_unban_user(user_id: int, username: str = Depends(get_current_admin)):
|
||
"""Разбанить"""
|
||
async with AsyncSessionLocal() as session:
|
||
await session.execute(update(User).where(User.user_id == user_id).values(is_banned=False))
|
||
await session.commit()
|
||
return JSONResponse({"success": True, "message": "Разбанен"})
|
||
|
||
|
||
@app.post("/api/user/{user_id}/verify")
|
||
async def api_verify_user(user_id: int, username: str = Depends(get_current_admin)):
|
||
"""Верифицировать"""
|
||
async with AsyncSessionLocal() as session:
|
||
await session.execute(update(User).where(User.user_id == user_id).values(
|
||
verified=True, verification_date=datetime.utcnow()))
|
||
await session.commit()
|
||
return JSONResponse({"success": True, "message": "Верифицирован"})
|
||
|
||
|
||
@app.post("/api/user/{user_id}/unverify")
|
||
async def api_unverify_user(user_id: int, username: str = Depends(get_current_admin)):
|
||
"""Отозвать верификацию"""
|
||
async with AsyncSessionLocal() as session:
|
||
await session.execute(update(User).where(User.user_id == user_id).values(verified=False))
|
||
await session.commit()
|
||
return JSONResponse({"success": True, "message": "Верификация отозвана"})
|
||
|
||
|
||
# ============================================================================
|
||
# ВЕРИФИКАЦИЯ
|
||
# ============================================================================
|
||
|
||
@app.get("/verification", response_class=HTMLResponse)
|
||
async def verification_page(request: Request, username: str = Depends(get_current_admin)):
|
||
"""Верификация"""
|
||
async with AsyncSessionLocal() as session:
|
||
pending = list((await session.execute(
|
||
select(VerificationRequest).where(VerificationRequest.status == 'pending')
|
||
.order_by(VerificationRequest.created_at.desc()).limit(50)
|
||
)).scalars().all())
|
||
unverified = list((await session.execute(
|
||
select(User).where(User.verified == False).order_by(User.join_date.desc()).limit(50)
|
||
)).scalars().all())
|
||
return templates.TemplateResponse("verification.html", {
|
||
"request": request, "username": username,
|
||
"pending_requests": pending, "unverified_users": unverified
|
||
})
|
||
|
||
|
||
@app.post("/api/verification/{req_id}/approve")
|
||
async def api_approve_verification(req_id: int, username: str = Depends(get_current_admin)):
|
||
"""Одобрить верификацию"""
|
||
async with AsyncSessionLocal() as session:
|
||
req = (await session.execute(select(VerificationRequest).where(
|
||
VerificationRequest.id == req_id))).scalar_one_or_none()
|
||
if req:
|
||
req.status = 'approved'
|
||
req.reviewed_at = datetime.utcnow()
|
||
await session.execute(update(User).where(User.user_id == req.user_id).values(
|
||
verified=True, apartment=req.apartment, verification_date=datetime.utcnow()))
|
||
await session.commit()
|
||
return JSONResponse({"success": True})
|
||
|
||
|
||
@app.post("/api/verification/{req_id}/reject")
|
||
async def api_reject_verification(req_id: int, username: str = Depends(get_current_admin)):
|
||
"""Отклонить верификацию"""
|
||
async with AsyncSessionLocal() as session:
|
||
req = (await session.execute(select(VerificationRequest).where(
|
||
VerificationRequest.id == req_id))).scalar_one_or_none()
|
||
if req:
|
||
req.status = 'rejected'
|
||
req.reviewed_at = datetime.utcnow()
|
||
await session.commit()
|
||
return JSONResponse({"success": True})
|
||
|
||
|
||
# ============================================================================
|
||
# ТЕЛЕФОНЫ И СЛУЖБЫ
|
||
# ============================================================================
|
||
|
||
@app.get("/phones", response_class=HTMLResponse)
|
||
async def phones_page(request: Request, username: str = Depends(get_current_admin)):
|
||
"""Телефоны и службы"""
|
||
async with AsyncSessionLocal() as session:
|
||
services = list((await session.execute(select(Service).order_by(Service.category, Service.name)
|
||
)).scalars().all())
|
||
return templates.TemplateResponse("phones.html", {
|
||
"request": request, "username": username, "services": services
|
||
})
|
||
|
||
|
||
@app.post("/api/service/add")
|
||
async def api_add_service(request: Request, username: str = Depends(get_current_admin)):
|
||
"""Добавить службу"""
|
||
data = await request.json()
|
||
async with AsyncSessionLocal() as session:
|
||
service = Service(
|
||
name=data['name'],
|
||
phone=data['phone'],
|
||
category=data.get('category', 'other'),
|
||
description=data.get('description', ''),
|
||
verified_by_admin=True,
|
||
image_path=data.get('image_path', None)
|
||
)
|
||
session.add(service)
|
||
await session.commit()
|
||
return JSONResponse({"success": True, "message": "Служба добавлена"})
|
||
|
||
|
||
@app.post("/api/service/upload_image")
|
||
async def api_upload_service_image(
|
||
file: UploadFile = File(...),
|
||
category: str = Form(...),
|
||
username: str = Depends(get_current_admin)
|
||
):
|
||
"""Загрузить картинку для службы"""
|
||
import os
|
||
import uuid
|
||
from pathlib import Path
|
||
|
||
# Создаём папку для картинок
|
||
images_dir = Path("data/service_images")
|
||
images_dir.mkdir(parents=True, exist_ok=True)
|
||
|
||
# Генерируем уникальное имя файла
|
||
file_extension = file.filename.split(".")[-1] if "." in file.filename else "jpg"
|
||
unique_filename = f"{category}_{uuid.uuid4().hex}.{file_extension}"
|
||
file_path = images_dir / unique_filename
|
||
|
||
# Сохраняем файл
|
||
try:
|
||
with open(file_path, "wb") as f:
|
||
content = await file.read()
|
||
f.write(content)
|
||
|
||
# Обновляем все службы этой категории
|
||
async with AsyncSessionLocal() as session:
|
||
await session.execute(
|
||
update(Service)
|
||
.where(Service.category == category)
|
||
.values(image_path=str(file_path))
|
||
)
|
||
await session.commit()
|
||
|
||
return JSONResponse({
|
||
"success": True,
|
||
"message": f"Картинка загружена",
|
||
"file_path": str(file_path)
|
||
})
|
||
except Exception as e:
|
||
logger.error(f"Ошибка загрузки картинки: {e}")
|
||
return JSONResponse({
|
||
"success": False,
|
||
"error": str(e)
|
||
}, status_code=500)
|
||
|
||
|
||
@app.post("/api/service/{service_id}/update")
|
||
async def api_update_service(service_id: int, request: Request,
|
||
username: str = Depends(get_current_admin)):
|
||
"""Обновить службу"""
|
||
data = await request.json()
|
||
async with AsyncSessionLocal() as session:
|
||
await session.execute(update(Service).where(Service.id == service_id).values(**data))
|
||
await session.commit()
|
||
return JSONResponse({"success": True})
|
||
|
||
|
||
@app.post("/api/service/{service_id}/delete")
|
||
async def api_delete_service(service_id: int, username: str = Depends(get_current_admin)):
|
||
"""Удалить службу"""
|
||
async with AsyncSessionLocal() as session:
|
||
await session.execute(delete(Service).where(Service.service_id == service_id))
|
||
await session.commit()
|
||
return JSONResponse({"success": True})
|
||
|
||
|
||
# ============================================================================
|
||
# ОБЪЯВЛЕНИЯ
|
||
# ============================================================================
|
||
|
||
@app.get("/ads", response_class=HTMLResponse)
|
||
async def ads_page(request: Request, username: str = Depends(get_current_admin)):
|
||
"""Объявления"""
|
||
async with AsyncSessionLocal() as session:
|
||
ads = list((await session.execute(select(Ad).order_by(Ad.created_at.desc()).limit(100)
|
||
)).scalars().all())
|
||
return templates.TemplateResponse("ads.html", {
|
||
"request": request, "username": username, "ads": ads
|
||
})
|
||
|
||
|
||
@app.post("/api/ad/add")
|
||
async def api_add_ad(request: Request, username: str = Depends(get_current_admin)):
|
||
"""Добавить объявление"""
|
||
data = await request.json()
|
||
async with AsyncSessionLocal() as session:
|
||
ad = Ad(
|
||
title=data['title'],
|
||
description=data.get('text', ''),
|
||
category=data.get('category', 'other'),
|
||
user_id=config.ADMIN_USER_ID,
|
||
is_active=data.get('is_active', True),
|
||
is_moderated=True
|
||
)
|
||
session.add(ad)
|
||
await session.commit()
|
||
return JSONResponse({"success": True, "message": "Объявление добавлено"})
|
||
|
||
|
||
@app.post("/api/ad/{ad_id}/delete")
|
||
async def api_delete_ad(ad_id: int, username: str = Depends(get_current_admin)):
|
||
"""Удалить объявление"""
|
||
async with AsyncSessionLocal() as session:
|
||
await session.execute(update(Ad).where(Ad.ad_id == ad_id).values(is_active=False))
|
||
await session.commit()
|
||
return JSONResponse({"success": True})
|
||
|
||
|
||
# ============================================================================
|
||
# РАССЫЛКИ
|
||
# ============================================================================
|
||
|
||
@app.get("/broadcast", response_class=HTMLResponse)
|
||
async def broadcast_page(request: Request, username: str = Depends(get_current_admin)):
|
||
"""Рассылки"""
|
||
return templates.TemplateResponse("broadcast.html", {
|
||
"request": request, "username": username
|
||
})
|
||
|
||
|
||
@app.post("/api/broadcast/send")
|
||
async def api_send_broadcast(request: Request, username: str = Depends(get_current_admin)):
|
||
"""Отправить рассылку"""
|
||
import requests
|
||
data = await request.json()
|
||
message_text = data.get('text', '')
|
||
|
||
# Отправляем только в чат дома (через бота)
|
||
url = f"https://api.telegram.org/bot{config.BOT_TOKEN}/sendMessage"
|
||
|
||
try:
|
||
# Используем requests с прокси если настроен
|
||
proxies = None
|
||
if config.USE_PROXY:
|
||
proxy_url = config.get_proxy_url()
|
||
if proxy_url:
|
||
proxies = {'http': proxy_url, 'https': proxy_url}
|
||
|
||
response = requests.post(url, json={
|
||
'chat_id': config.ADMIN_CHAT_ID,
|
||
'text': f"📢 <b>Объявление от администрации</b>\n\n{message_text}",
|
||
'parse_mode': 'HTML'
|
||
}, timeout=30, proxies=proxies)
|
||
|
||
result = response.json()
|
||
if result.get('ok'):
|
||
return JSONResponse({"success": True, "message": "Объявление отправлено в чат дома!"})
|
||
else:
|
||
return JSONResponse({"success": False, "error": str(result)})
|
||
except Exception as e:
|
||
logger.error(f"Ошибка отправки рассылки: {e}")
|
||
return JSONResponse({"success": False, "error": str(e)}, status_code=500)
|
||
|
||
|
||
# ============================================================================
|
||
# ОПРОСЫ
|
||
# ============================================================================
|
||
|
||
@app.get("/polls", response_class=HTMLResponse)
|
||
async def polls_page(request: Request, username: str = Depends(get_current_admin)):
|
||
"""Опросы"""
|
||
async with AsyncSessionLocal() as session:
|
||
polls = list((await session.execute(select(Poll).order_by(Poll.created_at.desc()).limit(50)
|
||
)).scalars().all())
|
||
return templates.TemplateResponse("polls.html", {
|
||
"request": request, "username": username, "polls": polls
|
||
})
|
||
|
||
|
||
@app.post("/api/poll/create")
|
||
async def api_create_poll(request: Request, username: str = Depends(get_current_admin)):
|
||
"""Создать опрос"""
|
||
data = await request.json()
|
||
async with AsyncSessionLocal() as session:
|
||
poll = Poll(
|
||
question=data['question'],
|
||
options=json.dumps(data['options']),
|
||
votes='{}',
|
||
created_by=config.ADMIN_USER_ID,
|
||
is_active=data.get('is_active', True),
|
||
message_id=0, # Заглушка
|
||
chat_id=config.ADMIN_CHAT_ID
|
||
)
|
||
session.add(poll)
|
||
await session.commit()
|
||
return JSONResponse({"success": True, "message": "Опрос создан"})
|
||
|
||
|
||
@app.post("/api/poll/{poll_id}/close")
|
||
async def api_close_poll(poll_id: int, username: str = Depends(get_current_admin)):
|
||
"""Закрыть опрос"""
|
||
async with AsyncSessionLocal() as session:
|
||
await session.execute(update(Poll).where(Poll.poll_id == poll_id).values(is_active=False))
|
||
await session.commit()
|
||
return JSONResponse({"success": True})
|
||
|
||
|
||
# ============================================================================
|
||
# СОБЫТИЯ
|
||
# ============================================================================
|
||
|
||
@app.get("/events", response_class=HTMLResponse)
|
||
async def events_page(request: Request, username: str = Depends(get_current_admin)):
|
||
"""События"""
|
||
async with AsyncSessionLocal() as session:
|
||
events = list((await session.execute(select(Event).order_by(Event.event_date.desc()).limit(50)
|
||
)).scalars().all())
|
||
return templates.TemplateResponse("events.html", {
|
||
"request": request, "username": username, "events": events
|
||
})
|
||
|
||
|
||
@app.post("/api/event/add")
|
||
async def api_add_event(request: Request, username: str = Depends(get_current_admin)):
|
||
"""Добавить событие"""
|
||
data = await request.json()
|
||
async with AsyncSessionLocal() as session:
|
||
event = Event(
|
||
title=data['title'], description=data.get('description', ''),
|
||
event_type=data.get('event_type', 'meeting'),
|
||
event_date=datetime.fromisoformat(data['event_date']),
|
||
created_by=config.ADMIN_USER_ID,
|
||
is_active=data.get('is_active', True)
|
||
)
|
||
session.add(event)
|
||
await session.commit()
|
||
return JSONResponse({"success": True, "message": "Событие добавлено"})
|
||
|
||
|
||
# ============================================================================
|
||
# РАСПИСАНИЯ
|
||
# ============================================================================
|
||
|
||
@app.get("/schedules", response_class=HTMLResponse)
|
||
async def schedules_page(request: Request, username: str = Depends(get_current_admin)):
|
||
"""Расписания"""
|
||
async with AsyncSessionLocal() as session:
|
||
schedules = list((await session.execute(select(Schedule).order_by(Schedule.start_time.desc())
|
||
)).scalars().all())
|
||
return templates.TemplateResponse("schedules.html", {
|
||
"request": request, "username": username, "schedules": schedules
|
||
})
|
||
|
||
|
||
@app.post("/api/schedule/add")
|
||
async def api_add_schedule(request: Request, username: str = Depends(get_current_admin)):
|
||
"""Добавить расписание"""
|
||
data = await request.json()
|
||
async with AsyncSessionLocal() as session:
|
||
schedule = Schedule(
|
||
title=data['title'], schedule_type=data.get('schedule_type', 'water'),
|
||
start_time=datetime.fromisoformat(data['start_time']),
|
||
end_time=datetime.fromisoformat(data['end_time']) if data.get('end_time') else None,
|
||
description=data.get('description', ''), is_active=data.get('is_active', True)
|
||
)
|
||
session.add(schedule)
|
||
await session.commit()
|
||
return JSONResponse({"success": True, "message": "Расписание добавлено"})
|
||
|
||
|
||
@app.post("/api/schedule/{schedule_id}/delete")
|
||
async def api_delete_schedule(schedule_id: int, username: str = Depends(get_current_admin)):
|
||
"""Удалить расписание"""
|
||
async with AsyncSessionLocal() as session:
|
||
await session.execute(update(Schedule).where(
|
||
Schedule.schedule_id == schedule_id).values(is_active=False))
|
||
await session.commit()
|
||
return JSONResponse({"success": True})
|
||
|
||
|
||
# ============================================================================
|
||
# ЭКСПОРТ
|
||
# ============================================================================
|
||
|
||
@app.get("/export", response_class=HTMLResponse)
|
||
async def export_page(request: Request, username: str = Depends(get_current_admin)):
|
||
"""Экспорт"""
|
||
return templates.TemplateResponse("export.html", {
|
||
"request": request, "username": username
|
||
})
|
||
|
||
|
||
@app.get("/api/export/json")
|
||
async def api_export_json(username: str = Depends(get_current_admin)):
|
||
"""Экспорт JSON"""
|
||
from services.analytics import ChatAnalytics
|
||
async with AsyncSessionLocal() as session:
|
||
analytics = ChatAnalytics(session)
|
||
filepath = await analytics.export_to_json()
|
||
return JSONResponse({"success": True, "filepath": filepath})
|
||
|
||
|
||
# ============================================================================
|
||
# НАСТРОЙКИ
|
||
# ============================================================================
|
||
|
||
@app.get("/settings", response_class=HTMLResponse)
|
||
async def settings_page(request: Request, username: str = Depends(get_current_admin)):
|
||
"""Настройки"""
|
||
return templates.TemplateResponse("settings.html", {
|
||
"request": request, "username": username,
|
||
"config": {
|
||
"bot_token": config.BOT_TOKEN[:20] + "...",
|
||
"admin_chat_id": config.ADMIN_CHAT_ID,
|
||
"admin_user_id": config.ADMIN_USER_ID,
|
||
"use_proxy": config.USE_PROXY,
|
||
"web_login": config.WEB_ADMIN_LOGIN
|
||
}
|
||
})
|
||
|
||
|
||
def run_web_server(host: str = "0.0.0.0", port: int = 8000):
|
||
"""Запуск веб-сервера"""
|
||
import uvicorn
|
||
uvicorn.run(app, host=host, port=port)
|
||
|
||
|
||
if __name__ == "__main__":
|
||
run_web_server()
|