Update db.py
Этот коммит содержится в:
+33
-117
@@ -1,4 +1,3 @@
|
|||||||
import configparser
|
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
@@ -10,12 +9,10 @@ import shutil
|
|||||||
logging.basicConfig(level=logging.INFO)
|
logging.basicConfig(level=logging.INFO)
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
BASE_DIR = "/root/amnezia-bot/awg"
|
CONFIG_FILE = 'files/config.json'
|
||||||
CONFIG_FILE = os.path.join(BASE_DIR, "files", "setting.ini")
|
USER_EXPIRATION_FILE = 'files/user_expiration.json'
|
||||||
USER_EXPIRATION_FILE = os.path.join(BASE_DIR, "files", "user_expiration.json")
|
USER_TELEGRAM_FILE = 'files/user_telegram.json'
|
||||||
USER_TELEGRAM_FILE = os.path.join(BASE_DIR, "files", "user_telegram.json")
|
PROMOCODES_FILE = 'files/promocodes.json'
|
||||||
PROMOCODES_FILE = os.path.join(BASE_DIR, "files", "promocodes.json")
|
|
||||||
PAYMENTS_FILE = os.path.join(BASE_DIR, "files", "payments.json")
|
|
||||||
|
|
||||||
def load_json(file_path, default=None):
|
def load_json(file_path, default=None):
|
||||||
"""Загружает JSON-файл, возвращает default при ошибке или отсутствии файла."""
|
"""Загружает JSON-файл, возвращает default при ошибке или отсутствии файла."""
|
||||||
@@ -39,94 +36,42 @@ def save_json(file_path, data):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
def get_config():
|
def get_config():
|
||||||
"""Возвращает конфигурацию из setting.ini."""
|
"""Возвращает конфигурацию из config.json."""
|
||||||
config = configparser.ConfigParser()
|
return load_json(CONFIG_FILE, {})
|
||||||
try:
|
|
||||||
config.read(CONFIG_FILE)
|
|
||||||
if 'Settings' not in config:
|
|
||||||
logger.error(f"Секция [Settings] не найдена в {CONFIG_FILE}")
|
|
||||||
return {}
|
|
||||||
settings = dict(config['Settings'])
|
|
||||||
# Преобразование pricing из JSON-строки в словарь
|
|
||||||
if 'pricing' in settings:
|
|
||||||
try:
|
|
||||||
settings['pricing'] = json.loads(settings['pricing'])
|
|
||||||
except json.JSONDecodeError:
|
|
||||||
logger.error("Ошибка парсинга pricing в setting.ini")
|
|
||||||
settings['pricing'] = {}
|
|
||||||
return settings
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"Ошибка чтения {CONFIG_FILE}: {str(e)}")
|
|
||||||
return {}
|
|
||||||
|
|
||||||
def add_admin(admin_id):
|
def add_admin(admin_id):
|
||||||
"""Добавляет ID администратора в конфигурацию."""
|
"""Добавляет ID администратора в конфигурацию."""
|
||||||
config = get_config()
|
config = get_config()
|
||||||
admin_ids = config.get('admin_ids', '').split(',') if config.get('admin_ids') else []
|
admin_ids = config.get('admin_ids', [])
|
||||||
admin_id_str = str(admin_id)
|
if str(admin_id) not in admin_ids:
|
||||||
if admin_id_str not in admin_ids:
|
admin_ids.append(str(admin_id))
|
||||||
admin_ids.append(admin_id_str)
|
config['admin_ids'] = admin_ids
|
||||||
config['admin_ids'] = ','.join([aid for aid in admin_ids if aid])
|
save_json(CONFIG_FILE, config)
|
||||||
config_parser = configparser.ConfigParser()
|
|
||||||
config_parser['Settings'] = config
|
|
||||||
try:
|
|
||||||
with open(CONFIG_FILE, 'w') as configfile:
|
|
||||||
config_parser.write(configfile)
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"Ошибка сохранения admin_ids в {CONFIG_FILE}: {str(e)}")
|
|
||||||
|
|
||||||
def remove_admin(admin_id):
|
def remove_admin(admin_id):
|
||||||
"""Удаляет ID администратора из конфигурации."""
|
"""Удаляет ID администратора из конфигурации."""
|
||||||
config = get_config()
|
config = get_config()
|
||||||
admin_ids = config.get('admin_ids', '').split(',') if config.get('admin_ids') else []
|
admin_ids = config.get('admin_ids', [])
|
||||||
admin_id_str = str(admin_id)
|
admin_id_str = str(admin_id)
|
||||||
if admin_id_str in admin_ids:
|
if admin_id_str in admin_ids:
|
||||||
admin_ids.remove(admin_id_str)
|
admin_ids.remove(admin_id_str)
|
||||||
config['admin_ids'] = ','.join([aid for aid in admin_ids if aid])
|
config['admin_ids'] = admin_ids
|
||||||
config_parser = configparser.ConfigParser()
|
save_json(CONFIG_FILE, config)
|
||||||
config_parser['Settings'] = config
|
|
||||||
try:
|
|
||||||
with open(CONFIG_FILE, 'w') as configfile:
|
|
||||||
config_parser.write(configfile)
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"Ошибка сохранения admin_ids в {CONFIG_FILE}: {str(e)}")
|
|
||||||
|
|
||||||
def set_yoomoney_config(token=None, wallet=None):
|
|
||||||
"""Обновляет настройки YooMoney в конфигурации."""
|
|
||||||
config = get_config()
|
|
||||||
if token:
|
|
||||||
config['yoomoney_token'] = token
|
|
||||||
if wallet:
|
|
||||||
config['yoomoney_wallet'] = wallet
|
|
||||||
config_parser = configparser.ConfigParser()
|
|
||||||
config_parser['Settings'] = config
|
|
||||||
try:
|
|
||||||
with open(CONFIG_FILE, 'w') as configfile:
|
|
||||||
config_parser.write(configfile)
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"Ошибка сохранения YooMoney настроек в {CONFIG_FILE}: {str(e)}")
|
|
||||||
|
|
||||||
def set_pricing(period, price):
|
def set_pricing(period, price):
|
||||||
"""Устанавливает цену для указанного периода подписки."""
|
"""Устанавливает цену для указанного периода подписки."""
|
||||||
config = get_config()
|
config = get_config()
|
||||||
pricing = config.get('pricing', {})
|
config['pricing'] = config.get('pricing', {})
|
||||||
pricing[period] = float(price)
|
config['pricing'][period] = price
|
||||||
config['pricing'] = json.dumps(pricing) # Сохраняем как JSON-строку
|
save_json(CONFIG_FILE, config)
|
||||||
config_parser = configparser.ConfigParser()
|
|
||||||
config_parser['Settings'] = config
|
|
||||||
try:
|
|
||||||
with open(CONFIG_FILE, 'w') as configfile:
|
|
||||||
config_parser.write(configfile)
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"Ошибка сохранения pricing в {CONFIG_FILE}: {str(e)}")
|
|
||||||
|
|
||||||
def root_add(name, ipv6=False):
|
def root_add(name, ipv6=False):
|
||||||
"""Добавляет нового пользователя через newclient.sh."""
|
"""Добавляет нового пользователя через newclient.sh."""
|
||||||
try:
|
try:
|
||||||
cmd = [os.path.join(BASE_DIR, 'newclient.sh'), name]
|
cmd = ['./newclient.sh', name]
|
||||||
if not ipv6:
|
if not ipv6:
|
||||||
cmd.append('--no-ipv6')
|
cmd.append('--no-ipv6')
|
||||||
process = subprocess.run(cmd, capture_output=True, text=True, cwd=BASE_DIR)
|
process = subprocess.run(cmd, capture_output=True, text=True)
|
||||||
if process.returncode == 0:
|
if process.returncode == 0:
|
||||||
return True
|
return True
|
||||||
logger.error(f"Ошибка добавления пользователя {name}: {process.stderr}")
|
logger.error(f"Ошибка добавления пользователя {name}: {process.stderr}")
|
||||||
@@ -138,7 +83,7 @@ def root_add(name, ipv6=False):
|
|||||||
def deactive_user_db(name):
|
def deactive_user_db(name):
|
||||||
"""Деактивирует пользователя через removeclient.sh."""
|
"""Деактивирует пользователя через removeclient.sh."""
|
||||||
try:
|
try:
|
||||||
process = subprocess.run([os.path.join(BASE_DIR, 'removeclient.sh'), name], capture_output=True, text=True, cwd=BASE_DIR)
|
process = subprocess.run(['./removeclient.sh', name], capture_output=True, text=True)
|
||||||
if process.returncode == 0:
|
if process.returncode == 0:
|
||||||
return True
|
return True
|
||||||
logger.error(f"Ошибка удаления пользователя {name}: {process.stderr}")
|
logger.error(f"Ошибка удаления пользователя {name}: {process.stderr}")
|
||||||
@@ -150,7 +95,7 @@ def deactive_user_db(name):
|
|||||||
def get_client_list():
|
def get_client_list():
|
||||||
"""Возвращает список клиентов (имя и конфигурация)."""
|
"""Возвращает список клиентов (имя и конфигурация)."""
|
||||||
clients = []
|
clients = []
|
||||||
users_dir = os.path.join(BASE_DIR, 'users')
|
users_dir = 'users'
|
||||||
if os.path.exists(users_dir):
|
if os.path.exists(users_dir):
|
||||||
for user_dir in os.listdir(users_dir):
|
for user_dir in os.listdir(users_dir):
|
||||||
user_path = os.path.join(users_dir, user_dir)
|
user_path = os.path.join(users_dir, user_dir)
|
||||||
@@ -165,16 +110,17 @@ def get_client_list():
|
|||||||
def get_active_list():
|
def get_active_list():
|
||||||
"""Возвращает список активных клиентов с последним handshake."""
|
"""Возвращает список активных клиентов с последним handshake."""
|
||||||
active = []
|
active = []
|
||||||
try:
|
users_dir = 'users'
|
||||||
result = subprocess.run(['wg', 'show', 'wg0', 'latest-handshakes'], capture_output=True, text=True)
|
if os.path.exists(users_dir):
|
||||||
lines = result.stdout.strip().split('\n')
|
for user_dir in os.listdir(users_dir):
|
||||||
for line in lines:
|
user_path = os.path.join(users_dir, user_dir)
|
||||||
if line:
|
if os.path.isdir(user_path):
|
||||||
parts = line.split()
|
status_file = os.path.join(user_path, 'status.json')
|
||||||
if len(parts) >= 2:
|
if os.path.exists(status_file):
|
||||||
active.append((parts[0], datetime.fromtimestamp(int(parts[1])).strftime('%Y-%m-%d %H:%M:%S')))
|
with open(status_file, 'r') as f:
|
||||||
except Exception as e:
|
status = json.load(f)
|
||||||
logger.error(f"Ошибка получения активных клиентов: {str(e)}")
|
last_handshake = status.get('last_handshake', 'never')
|
||||||
|
active.append((user_dir, last_handshake))
|
||||||
return active
|
return active
|
||||||
|
|
||||||
def set_user_expiration(username, expiration, transfer_limit):
|
def set_user_expiration(username, expiration, transfer_limit):
|
||||||
@@ -217,7 +163,7 @@ def add_promocode(code, discount, expires_at, max_uses, subscription_period):
|
|||||||
if code in promocodes:
|
if code in promocodes:
|
||||||
return False
|
return False
|
||||||
promocodes[code] = {
|
promocodes[code] = {
|
||||||
'discount': float(discount),
|
'discount': discount,
|
||||||
'expires_at': expires_at.isoformat() if expires_at else None,
|
'expires_at': expires_at.isoformat() if expires_at else None,
|
||||||
'max_uses': max_uses,
|
'max_uses': max_uses,
|
||||||
'uses': 0,
|
'uses': 0,
|
||||||
@@ -266,33 +212,3 @@ def remove_promocode(code):
|
|||||||
save_json(PROMOCODES_FILE, promocodes)
|
save_json(PROMOCODES_FILE, promocodes)
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def add_payment(user_id, payment_id, amount, status, period=None):
|
|
||||||
"""Добавляет информацию о платеже."""
|
|
||||||
payments = load_json(PAYMENTS_FILE, {})
|
|
||||||
payments[payment_id] = {
|
|
||||||
'user_id': user_id,
|
|
||||||
'amount': float(amount),
|
|
||||||
'status': status,
|
|
||||||
'period': period,
|
|
||||||
'created_at': datetime.now(pytz.utc).isoformat()
|
|
||||||
}
|
|
||||||
save_json(PAYMENTS_FILE, payments)
|
|
||||||
|
|
||||||
def update_payment_status(payment_id, status):
|
|
||||||
"""Обновляет статус платежа."""
|
|
||||||
payments = load_json(PAYMENTS_FILE, {})
|
|
||||||
if payment_id in payments:
|
|
||||||
payments[payment_id]['status'] = status
|
|
||||||
save_json(PAYMENTS_FILE, payments)
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
def get_pending_payments():
|
|
||||||
"""Возвращает список незавершенных платежей."""
|
|
||||||
payments = load_json(PAYMENTS_FILE, {})
|
|
||||||
return [
|
|
||||||
(p['user_id'], payment_id, p['amount'], p['period'])
|
|
||||||
for payment_id, p in payments.items()
|
|
||||||
if p['status'] == 'pending'
|
|
||||||
]
|
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user