Compare commits
42 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5fa69dec3e | |||
| 3d5f3303d1 | |||
| 10883e92b1 | |||
| e2d28333ec | |||
| 6d55d4832f | |||
| 46c563873f | |||
| 10c5d3c408 | |||
| 942080c460 | |||
| 6a0869ca0a | |||
| d9992dd2f2 | |||
| c8c9631518 | |||
| 943f29f227 | |||
| 80a069077c | |||
| e344e55e6a | |||
| a69947b69a | |||
| 926f593f50 | |||
| f13734a4e9 | |||
| 2107166926 | |||
| 60e5601690 | |||
| 0957d9ef88 | |||
| eb481c57ec | |||
| e0b1666f5d | |||
| f2afc088af | |||
| 971d59b2c6 | |||
| 83fe58056f | |||
| 5f107922d0 | |||
| a2ea6b7bf7 | |||
| 1e0e728840 | |||
| cea6ed3f95 | |||
| f15705ed47 | |||
| 0b9c13ae4b | |||
| d0c8ae02f0 | |||
| 4eda7401b9 | |||
| 0c2f3c9399 | |||
| 541ecae48c | |||
| 82a551f1d4 | |||
| fd2253135d | |||
| d0820aa47e | |||
| 09c5800f49 | |||
| 52aa2dc6a8 | |||
| 6418ee7735 | |||
| 25aef89b4f |
@@ -1,31 +1,28 @@
|
||||
name: BedolagaBot
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
uses: actions/checkout@v4
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
|
||||
uses: docker/setup-buildx-action@v3
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v2
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
|
||||
- name: Build and push Docker image
|
||||
uses: docker/build-push-action@v4
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile
|
||||
platforms: linux/amd64,linux/arm64
|
||||
push: true
|
||||
tags: fr1ngg/remnawave-bedolaga-telegram-bot:latest
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
@@ -0,0 +1,66 @@
|
||||
name: Build and Publish Docker Image
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- master
|
||||
tags:
|
||||
- 'v*'
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
- master
|
||||
env:
|
||||
REGISTRY: ghcr.io
|
||||
IMAGE_NAME: fr1ngg/remnawave-bedolaga-telegram-bot
|
||||
jobs:
|
||||
build-and-push:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
- name: Log in to Container Registry
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Extract metadata
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||
tags: |
|
||||
type=ref,event=branch
|
||||
type=ref,event=pr
|
||||
type=semver,pattern={{version}}
|
||||
type=semver,pattern={{major}}.{{minor}}
|
||||
type=semver,pattern={{major}}
|
||||
type=raw,value=latest,enable={{is_default_branch}}
|
||||
- name: Build and push Docker image
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile
|
||||
platforms: linux/amd64,linux/arm64
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
- name: Generate security report
|
||||
uses: docker/scout-action@v1
|
||||
if: github.event_name == 'pull_request'
|
||||
with:
|
||||
command: quickview,compare
|
||||
image: ${{ steps.meta.outputs.tags }}
|
||||
to: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
|
||||
ignore-unchanged: true
|
||||
only-severities: critical,high
|
||||
write-comment: true
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -1,96 +0,0 @@
|
||||
# RemnaWave Bot Docker Management
|
||||
|
||||
.PHONY: help build up down restart logs clean db-backup db-restore
|
||||
|
||||
# Default target
|
||||
help:
|
||||
@echo "Available commands:"
|
||||
@echo " build - Build all Docker images"
|
||||
@echo " up - Start all services"
|
||||
@echo " up-min - Start only bot and database (minimal setup)"
|
||||
@echo " up-full - Start all services including nginx and redis"
|
||||
@echo " down - Stop all services"
|
||||
@echo " restart - Restart all services"
|
||||
@echo " logs - Show logs for all services"
|
||||
@echo " logs-bot - Show logs for bot service only"
|
||||
@echo " logs-db - Show logs for database service only"
|
||||
@echo " clean - Remove all containers, networks, and volumes"
|
||||
@echo " db-backup - Create database backup"
|
||||
@echo " db-restore - Restore database from backup"
|
||||
@echo " shell-bot - Open shell in bot container"
|
||||
@echo " shell-db - Open shell in database container"
|
||||
|
||||
# Build all images
|
||||
build:
|
||||
docker compose build
|
||||
|
||||
# Start minimal services (bot + database)
|
||||
up-min: setup-dirs
|
||||
docker compose up -d postgres bot
|
||||
|
||||
# Start all services including optional ones
|
||||
up-full: setup-dirs
|
||||
docker compose --profile with-nginx up -d
|
||||
|
||||
# Start main services (default)
|
||||
up: setup-dirs
|
||||
docker compose up -d postgres redis bot
|
||||
|
||||
# Setup required directories
|
||||
setup-dirs:
|
||||
mkdir -p logs data backups
|
||||
|
||||
# Stop all services
|
||||
down:
|
||||
docker compose down
|
||||
|
||||
# Restart all services
|
||||
restart:
|
||||
docker compose restart
|
||||
|
||||
# Show logs for all services
|
||||
logs:
|
||||
docker compose logs -f
|
||||
|
||||
# Show logs for bot only
|
||||
logs-bot:
|
||||
docker compose logs -f bot
|
||||
|
||||
# Show logs for database only
|
||||
logs-db:
|
||||
docker compose logs -f postgres
|
||||
|
||||
# Clean up everything (DANGEROUS - removes all data)
|
||||
clean:
|
||||
@echo "This will remove all containers, networks, and volumes. Are you sure? [y/N]"
|
||||
@read answer && [ "$$answer" = "y" ] || [ "$$answer" = "Y" ]
|
||||
docker compose down -v --remove-orphans
|
||||
docker system prune -f
|
||||
|
||||
# Database backup
|
||||
db-backup:
|
||||
@mkdir -p backups
|
||||
docker compose exec postgres pg_dump -U remnawave_user remnawave_bot > backups/backup_$(shell date +%Y%m%d_%H%M%S).sql
|
||||
@echo "Backup created in backups/ directory"
|
||||
|
||||
# Database restore (use: make db-restore BACKUP=backup_20231201_120000.sql)
|
||||
db-restore:
|
||||
@if [ -z "$(BACKUP)" ]; then echo "Usage: make db-restore BACKUP=backup_file.sql"; exit 1; fi
|
||||
docker compose exec -T postgres psql -U remnawave_user -d remnawave_bot < backups/$(BACKUP)
|
||||
@echo "Database restored from $(BACKUP)"
|
||||
|
||||
# Open shell in bot container
|
||||
shell-bot:
|
||||
docker compose exec bot /bin/bash
|
||||
|
||||
# Open shell in database container
|
||||
shell-db:
|
||||
docker compose exec postgres psql -U remnawave_user -d remnawave_bot
|
||||
|
||||
# Check services status
|
||||
status:
|
||||
docker compose ps
|
||||
|
||||
# View service resource usage
|
||||
stats:
|
||||
docker stats --format "table {{.Container}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.NetIO}}\t{{.BlockIO}}"
|
||||
@@ -29,9 +29,9 @@
|
||||
### 👤 **Для пользователей**
|
||||
- 💰 **Управление балансом** - Telegram Stars + Telegram Tribute + P2P через поддержку
|
||||
- 🛒 **Покупка подписок** - различные тарифы с настройкой squad
|
||||
- 📱 **Управление подписками** - просмотр, продление, ссылки
|
||||
- 📱 **Управление подписками** - просмотр, продление, ссылки, настройка автопродления
|
||||
- 🎁 **Промокоды** - денежные бонусы
|
||||
- 👥 **Реферальная программа** - зарабатывай с друзей
|
||||
- 👥 **Реферальная программа** - зарабатывай с друзей и их последующих пополнений
|
||||
- 🎰 **Игра удачи** - ежедневные бонусы
|
||||
- 🆓 **Тестовая подписка** - бесплатная пробная версия
|
||||
- ♾️ **Автопродление** - настраиваемое автообновление
|
||||
@@ -55,87 +55,40 @@
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
---
|
||||
# 🚀 Автоматический установщик
|
||||
|
||||
## 🚀 Быстрый старт
|
||||
(ТЕСТИРУЕТСЯ, ДРУЗЬЯ КАК БЫ ВАМ НЕ ХОТЕЛОСЬ, ЧТОБЫ ВСЕ САМО ПОСТАВИЛОСЬ, НО Я ПОКА НЕ МОГУ ЗАСТАВИТЬ СКРИПТ КОРРЕКТНО НАСТРАИВАТЬ ВАМ ВЕБХУК С ОБРАТНЫМ ПРОКСИ, ПОЭТОМУ СОБИРАЕМ РУЧКАМИ ДОКЕР БОТА, ПОДКЛЮЧАЕМ ЕГО К СЕТИ ВАШЕГО NGINX/CADDY ДОКЕРА. ДЕЛАЕМ РУЧКАМИ ОБРАТНО ПРОКСИ НА ХУК /tribute-webhook И КАЙФУЕМ - НЕЙРОНКА КЛАУД В ПОМОЩЬ)
|
||||
|
||||
### ⚡ Автоматическая установка (Ubuntu)
|
||||
## Структура проекта
|
||||
|
||||
Установите бота **одной командой** с интерактивным мастером настройки:
|
||||
После установки в `/opt/bedolaga-bot/`:
|
||||
|
||||
```bash
|
||||
curl -sSL https://github.com/Fr1ngg/remnawave-bedolaga-telegram-bot/raw/main/bedolaga.sh | sudo bash
|
||||
```
|
||||
/opt/bedolaga-bot/
|
||||
├── docker-compose.yml # Конфигурация контейнеров
|
||||
├── .env # Переменные окружения
|
||||
├── logs/ # Логи бота
|
||||
├── data/ # Данные приложения
|
||||
└── backups/ # Резервные копии БД
|
||||
```
|
||||
|
||||
<details>
|
||||
<summary>🔧 Что делает установщик</summary>
|
||||
|
||||
- ✅ Обновляет систему Ubuntu
|
||||
- ✅ Устанавливает Docker и зависимости
|
||||
- ✅ Создает структуру проекта в `/opt/bedolaga-bot`
|
||||
- ✅ Интерактивная настройка всех параметров
|
||||
- ✅ Создает systemd службу (опционально)
|
||||
- ✅ Запускает удобное меню управления
|
||||
|
||||
</details>
|
||||
|
||||
### 🎛 Интерактивное меню управления
|
||||
|
||||
После установки вы получаете полнофункциональное меню:
|
||||
|
||||
<img width="500" alt="Интерфейс управления ботом" src="https://github.com/user-attachments/assets/9ab876f5-2758-4c52-93dd-6c9c654a07aa">
|
||||
|
||||
**Доступные действия:**
|
||||
- 🚀 Запуск/остановка/перезапуск бота
|
||||
- 📺 Просмотр логов в реальном времени
|
||||
- 💾 Создание и восстановление резервных копий БД
|
||||
- ✏️ Редактирование конфигурации
|
||||
- 🩺 Диагностика и устранение проблем
|
||||
- 🔄 Автообновление бота
|
||||
|
||||
---
|
||||
|
||||
## 📖 Документация
|
||||
> 💡 **Совет:** После установки добавьте установщик в закладки для быстрого доступа к меню управления!
|
||||
|
||||
### 🎯 Варианты установки
|
||||
## 💡 Полезные команды
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>Сценарий</th>
|
||||
<th>Описание</th>
|
||||
<th>Команда</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>🏠 <strong>Локальная установка</strong></td>
|
||||
<td>Панель + бот на одном сервере</td>
|
||||
<td><code>./bedolaga.sh</code> → вариант 2</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>🌐 <strong>Удаленная установка</strong></td>
|
||||
<td>Бот отдельно от панели</td>
|
||||
<td><code>./bedolaga.sh</code> → вариант 1</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>⚡ <strong>Расширенная</strong></td>
|
||||
<td>С Redis и Nginx</td>
|
||||
<td><code>./bedolaga.sh</code> → вариант 3</td>
|
||||
</tr>
|
||||
</table>
|
||||
# Быстрый перезапуск
|
||||
docker compose restart
|
||||
|
||||
### ⚙️ Ключевые настройки
|
||||
# Очистка логов
|
||||
docker compose logs --tail=100
|
||||
|
||||
<details>
|
||||
<summary>📋 Основные параметры</summary>
|
||||
# Проверка использования ресурсов
|
||||
docker stats
|
||||
|
||||
| Переменная | Описание | Пример |
|
||||
|------------|----------|---------|
|
||||
| `BOT_TOKEN` | Токен от [@BotFather](https://t.me/BotFather) | `123456:ABC-DEF...` |
|
||||
| `BOT_USERNAME` | Username бота (без @) | `your_bot` |
|
||||
| `REMNAWAVE_URL` | URL панели Remnawave | `https://panel.com` |
|
||||
| `REMNAWAVE_TOKEN` | API токен панели | `your_api_token` |
|
||||
| `ADMIN_IDS` | ID администраторов | `123456789,987654321` |
|
||||
|
||||
</details>
|
||||
# Резервная копия одной командой
|
||||
docker compose exec postgres pg_dump -U remnawave_user remnawave_bot > backup.sql
|
||||
|
||||
<details>
|
||||
<summary>🎁 Реферальная программа</summary>
|
||||
@@ -257,7 +210,7 @@ curl -sSL https://github.com/Fr1ngg/remnawave-bedolaga-telegram-bot/raw/main/bed
|
||||
|
||||
3.3 Рестартим Бота, рестратим Caddy/Nginx
|
||||
|
||||
4) Указываем ссылку на наш хук в настройках Tribute: https://test.example.com/tribute-webhook
|
||||
4) Указываем ссылку на наш хук в настройках Tribute: https://test.example.com/tribute-webhook, создаем API ключ вписываем в .env бота
|
||||
|
||||
5) Делаем тест - если успешно, значит все настроили правильно. Не успешный тест - проверяй доступность хука, где-то ты что-то не так настроил
|
||||
|
||||
@@ -621,7 +574,8 @@ emergency-fix:
|
||||
|
||||
### 📞 Контакты
|
||||
|
||||
- **Telegram:** [@fringg](https://t.me/fringg)
|
||||
- **Telegram:** [@fringg](https://t.me/fringg) - Писать исключительно по делу, я бы конечно был рад всем помочь настроить remnawave, ваши ноды, настроить вам бота, настроить вебхуки, но ребят я один и бота пилю тоже в соло, помощь вам занимает крайне много времени, поэтому если надумаете просить помочь что-то настроить, готовьтесь дарить мне шпагу подарком в тг)(
|
||||
|
||||
- **Issues:** [GitHub Issues](https://github.com/Fr1ngg/remnawave-bedolaga-telegram-bot/issues)
|
||||
- **Discussions:** [GitHub Discussions](https://github.com/Fr1ngg/remnawave-bedolaga-telegram-bot/discussions)
|
||||
|
||||
@@ -642,16 +596,43 @@ emergency-fix:
|
||||
|
||||
<div align="center">
|
||||
|
||||
### 🌟 Понравился проект? Поставьте звезду!
|
||||
## ⭐ История проекта
|
||||
|
||||
<div align="center">
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
[](https://star-history.com/#Fr1ngg/remnawave-bedolaga-telegram-bot&Date)
|
||||
|
||||
</div>
|
||||
|
||||
---
|
||||
|
||||
### 💝 Донатеры
|
||||
|
||||
Спасибо всем, кто поддерживает проект!
|
||||
|
||||
| Донатер | Сумма |
|
||||
|---------|-------|
|
||||
| Илья (@ispanec_nn) | $15 |
|
||||
| @Legacyyy777 | 600 руб |
|
||||
|
||||
---
|
||||
|
||||
### Поддержать проект
|
||||
[](https://t.me/tribute/app?startapp=duUO)
|
||||
|
||||
---
|
||||
|
||||
**💝 Создано с любовью для Remnawave сообщества**
|
||||
|
||||
*Автор не является профессиональным разработчиком, но прикладывает все усилия для создания удобного бота для ваших сервисов* 💪
|
||||
|
||||
*The English Readme is currently being written, with revisions for various payment systems and languages. If you have the opportunity, please help me with local optimization and translations. This would greatly help me in writing an open source project that is accessible to different markets/countries.*
|
||||
|
||||
[🔝 Вернуться наверх](#-remnawave-bedolaga-bot)
|
||||
|
||||
</div>
|
||||
|
||||
+1168
-1223
File diff suppressed because it is too large
Load Diff
@@ -1,102 +0,0 @@
|
||||
|
||||
services:
|
||||
# PostgreSQL Database
|
||||
postgres:
|
||||
image: postgres:15-alpine
|
||||
container_name: remnawave_bot_db
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
POSTGRES_DB: remnawave_bot
|
||||
POSTGRES_USER: remnawave_user
|
||||
POSTGRES_PASSWORD: secure_password_123
|
||||
POSTGRES_INITDB_ARGS: "--encoding=UTF-8 --lc-collate=C --lc-ctype=C"
|
||||
volumes:
|
||||
- postgres_data:/var/lib/postgresql/data
|
||||
- ./init-db.sql:/docker-entrypoint-initdb.d/init-db.sql:ro
|
||||
ports:
|
||||
- "5432:5432"
|
||||
networks:
|
||||
- bot_network
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U remnawave_user -d remnawave_bot"]
|
||||
interval: 15s
|
||||
timeout: 10s
|
||||
retries: 5
|
||||
start_period: 30s
|
||||
|
||||
# RemnaWave Bot
|
||||
bot:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
container_name: remnawave_bot
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
env_file:
|
||||
- .env
|
||||
environment:
|
||||
# Override database URL to use PostgreSQL container
|
||||
DATABASE_URL: postgresql+asyncpg://remnawave_user:secure_password_123@postgres:5432/remnawave_bot
|
||||
volumes:
|
||||
- ./logs:/app/logs
|
||||
- ./data:/app/data
|
||||
networks:
|
||||
- bot_network
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "python -c 'print(\"Bot is running\")'"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 30s
|
||||
|
||||
# Redis (optional, for caching and session storage)
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
container_name: remnawave_bot_redis
|
||||
restart: unless-stopped
|
||||
command: redis-server --appendonly yes --requirepass redis_password_123
|
||||
volumes:
|
||||
- redis_data:/data
|
||||
ports:
|
||||
- "6379:6379"
|
||||
networks:
|
||||
- bot_network
|
||||
healthcheck:
|
||||
test: ["CMD", "redis-cli", "--raw", "incr", "ping"]
|
||||
interval: 10s
|
||||
timeout: 3s
|
||||
retries: 5
|
||||
|
||||
# Nginx (optional, for serving static files or reverse proxy)
|
||||
nginx:
|
||||
image: nginx:alpine
|
||||
container_name: remnawave_bot_nginx
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
volumes:
|
||||
- ./nginx.conf:/etc/nginx/nginx.conf:ro
|
||||
- ./ssl:/etc/nginx/ssl:ro
|
||||
- ./static:/usr/share/nginx/html:ro
|
||||
networks:
|
||||
- bot_network
|
||||
depends_on:
|
||||
- bot
|
||||
profiles:
|
||||
- with-nginx
|
||||
|
||||
volumes:
|
||||
postgres_data:
|
||||
driver: local
|
||||
redis_data:
|
||||
driver: local
|
||||
|
||||
networks:
|
||||
bot_network:
|
||||
driver: bridge
|
||||
ipam:
|
||||
config:
|
||||
- subnet: 172.20.0.0/16
|
||||
@@ -1,100 +0,0 @@
|
||||
"""
|
||||
Экстренное исправление проблемы с отображением подписок
|
||||
Этот патч добавляет недостающие поля в таблицу user_subscriptions
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import sys
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
# Добавляем корневую директорию в путь
|
||||
sys.path.insert(0, str(Path(__file__).parent))
|
||||
|
||||
from config import load_config
|
||||
from database import Database
|
||||
from sqlalchemy import text
|
||||
import logging
|
||||
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
async def check_and_add_column(db, column_name, column_definition):
|
||||
"""Проверяет и добавляет колонку в таблицу"""
|
||||
try:
|
||||
# Отдельная транзакция для проверки
|
||||
async with db.engine.begin() as conn:
|
||||
await conn.execute(text(f"SELECT {column_name} FROM user_subscriptions LIMIT 1"))
|
||||
logger.info(f"✅ Поле {column_name} уже существует")
|
||||
return True
|
||||
except Exception:
|
||||
# Отдельная транзакция для добавления колонки
|
||||
try:
|
||||
async with db.engine.begin() as conn:
|
||||
logger.info(f"➕ Добавляю поле {column_name}...")
|
||||
await conn.execute(text(f"""
|
||||
ALTER TABLE user_subscriptions
|
||||
ADD COLUMN {column_name} {column_definition}
|
||||
"""))
|
||||
logger.info(f"✅ Поле {column_name} добавлено")
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.error(f"❌ Ошибка при добавлении {column_name}: {e}")
|
||||
return False
|
||||
|
||||
async def emergency_fix():
|
||||
"""Экстренное исправление базы данных"""
|
||||
|
||||
try:
|
||||
# Загружаем конфигурацию
|
||||
config = load_config()
|
||||
|
||||
# Подключаемся к базе данных
|
||||
db = Database(config.DATABASE_URL)
|
||||
|
||||
logger.info("🔧 Выполняю экстренное исправление базы данных...")
|
||||
|
||||
# Проверяем существование таблицы user_subscriptions
|
||||
try:
|
||||
async with db.engine.begin() as conn:
|
||||
result = await conn.execute(text("SELECT COUNT(*) FROM user_subscriptions"))
|
||||
count = result.scalar()
|
||||
logger.info(f"📊 Найдено {count} подписок в таблице user_subscriptions")
|
||||
except Exception as e:
|
||||
logger.error(f"❌ Таблица user_subscriptions не найдена: {e}")
|
||||
await db.close()
|
||||
return
|
||||
|
||||
# Добавляем поля по одному в отдельных транзакциях
|
||||
success1 = await check_and_add_column(db, "auto_pay_enabled", "BOOLEAN DEFAULT FALSE")
|
||||
success2 = await check_and_add_column(db, "auto_pay_days_before", "INTEGER DEFAULT 3")
|
||||
|
||||
# Финальная проверка в отдельной транзакции
|
||||
if success1 and success2:
|
||||
try:
|
||||
async with db.engine.begin() as conn:
|
||||
result = await conn.execute(text("""
|
||||
SELECT id, auto_pay_enabled, auto_pay_days_before
|
||||
FROM user_subscriptions LIMIT 1
|
||||
"""))
|
||||
row = result.fetchone()
|
||||
if row:
|
||||
logger.info("✅ Все поля доступны для чтения")
|
||||
logger.info(f"🔍 Пример записи: id={row[0]}, auto_pay_enabled={row[1]}, auto_pay_days_before={row[2]}")
|
||||
else:
|
||||
logger.info("✅ Все поля доступны, но таблица пуста")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"❌ Поля все еще недоступны: {e}")
|
||||
else:
|
||||
logger.error("❌ Не удалось добавить все необходимые поля")
|
||||
|
||||
await db.close()
|
||||
logger.info("🎉 Экстренное исправление завершено!")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"💥 Критическая ошибка: {e}")
|
||||
raise
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(emergency_fix())
|
||||
+34
-4
@@ -176,14 +176,14 @@ async def language_callback(callback: CallbackQuery, state: FSMContext, db: Data
|
||||
async def show_main_menu(message: Message, lang: str, is_admin: bool = False, user_id: int = None, db: Database = None, config: Config = None):
|
||||
try:
|
||||
show_trial = False
|
||||
show_lucky_game = True
|
||||
show_lucky_game = False
|
||||
|
||||
if config and config.TRIAL_ENABLED and user_id and db:
|
||||
has_used = await db.has_used_trial(user_id)
|
||||
show_trial = not has_used
|
||||
|
||||
if config:
|
||||
show_lucky_game = getattr(config, 'LUCKY_GAME_ENABLED', True)
|
||||
if config and hasattr(config, 'LUCKY_GAME_ENABLED'):
|
||||
show_lucky_game = config.LUCKY_GAME_ENABLED
|
||||
|
||||
await message.answer(
|
||||
t('main_menu', lang),
|
||||
@@ -193,6 +193,22 @@ async def show_main_menu(message: Message, lang: str, is_admin: bool = False, us
|
||||
logger.error(f"Error showing main menu: {e}")
|
||||
await message.answer("❌ Ошибка отображения меню")
|
||||
|
||||
def get_main_menu_keyboard(lang: str, is_admin: bool = False, config: Config = None, db: Database = None, user_id: int = None):
|
||||
show_trial = False
|
||||
show_lucky_game = False
|
||||
|
||||
if config and config.TRIAL_ENABLED and user_id and db:
|
||||
try:
|
||||
pass
|
||||
except:
|
||||
pass
|
||||
|
||||
if config and hasattr(config, 'LUCKY_GAME_ENABLED'):
|
||||
show_lucky_game = config.LUCKY_GAME_ENABLED
|
||||
|
||||
return main_menu_keyboard(lang, is_admin, show_trial, show_lucky_game)
|
||||
|
||||
|
||||
@router.callback_query(F.data == "main_menu")
|
||||
async def main_menu_callback(callback: CallbackQuery, **kwargs):
|
||||
user = kwargs.get('user')
|
||||
@@ -204,6 +220,7 @@ async def main_menu_callback(callback: CallbackQuery, **kwargs):
|
||||
return
|
||||
|
||||
show_trial = False
|
||||
show_lucky_game = False
|
||||
|
||||
if config and config.TRIAL_ENABLED and db:
|
||||
try:
|
||||
@@ -212,9 +229,12 @@ async def main_menu_callback(callback: CallbackQuery, **kwargs):
|
||||
except Exception as e:
|
||||
logger.error(f"Error checking trial availability: {e}")
|
||||
|
||||
if config and hasattr(config, 'LUCKY_GAME_ENABLED'):
|
||||
show_lucky_game = config.LUCKY_GAME_ENABLED
|
||||
|
||||
await callback.message.edit_text(
|
||||
t('main_menu', user.language),
|
||||
reply_markup=main_menu_keyboard(user.language, user.is_admin, show_trial)
|
||||
reply_markup=main_menu_keyboard(user.language, user.is_admin, show_trial, show_lucky_game)
|
||||
)
|
||||
|
||||
@router.callback_query(F.data == "trial_subscription")
|
||||
@@ -1126,6 +1146,16 @@ async def confirm_extend_subscription_callback(callback: CallbackQuery, db: Data
|
||||
|
||||
if result:
|
||||
logger.info(f"Successfully updated RemnaWave user expiry")
|
||||
|
||||
try:
|
||||
traffic_reset = await api.reset_user_traffic(user_uuid)
|
||||
if traffic_reset:
|
||||
logger.info(f"Successfully reset traffic for user {user_uuid}")
|
||||
else:
|
||||
logger.warning(f"Failed to reset traffic for user {user_uuid}")
|
||||
except Exception as traffic_error:
|
||||
logger.error(f"Error resetting traffic for user {user_uuid}: {traffic_error}")
|
||||
|
||||
else:
|
||||
logger.warning(f"Failed to update user in RemnaWave")
|
||||
|
||||
|
||||
+1
-1
@@ -13,7 +13,7 @@ def language_keyboard() -> InlineKeyboardMarkup:
|
||||
])
|
||||
return keyboard
|
||||
|
||||
def main_menu_keyboard(lang: str = 'ru', is_admin: bool = False, show_trial: bool = False, show_lucky_game: bool = True) -> InlineKeyboardMarkup:
|
||||
def main_menu_keyboard(lang: str = 'ru', is_admin: bool = False, show_trial: bool = False, show_lucky_game: bool = False) -> InlineKeyboardMarkup:
|
||||
buttons = [
|
||||
[
|
||||
InlineKeyboardButton(text="💰 " + t('balance', lang), callback_data="balance"),
|
||||
|
||||
@@ -233,6 +233,7 @@ TRANSLATIONS = {
|
||||
'payment_history': 'Payment history',
|
||||
'topup_card': 'Card payment',
|
||||
'topup_support': 'Through support',
|
||||
'your_subscriptions': 'Your Subscriptions',
|
||||
'back': 'Back',
|
||||
'no_subscriptions': '❌ You have no active subscriptions',
|
||||
'subscription_info': '📋 Subscription: {name}\n💰 Price: ${price:.2f}\n⏱ Duration: {days} days\n📊 Traffic: {traffic}\n\n{description}',
|
||||
@@ -269,6 +270,7 @@ TRANSLATIONS = {
|
||||
'total_referrals': 'Total invited',
|
||||
'active_referrals': 'Active referrals',
|
||||
'total_earned': 'Total earned',
|
||||
'language_changed': 'Language chanched ✅',
|
||||
'my_referrals': 'My referrals',
|
||||
'referral_reward_referrer': 'For each invited: $150',
|
||||
'referral_reward_referred': 'Newbie bonus: $150 after topping up $300',
|
||||
|
||||
Reference in New Issue
Block a user