diff --git a/awg/db.py b/awg/db.py index 6bf6fa6..cb78d1b 100644 --- a/awg/db.py +++ b/awg/db.py @@ -1,4 +1,3 @@ -import configparser import json import os import subprocess @@ -10,12 +9,10 @@ import shutil logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) -BASE_DIR = "/root/amnezia-bot/awg" -CONFIG_FILE = os.path.join(BASE_DIR, "files", "setting.ini") -USER_EXPIRATION_FILE = os.path.join(BASE_DIR, "files", "user_expiration.json") -USER_TELEGRAM_FILE = os.path.join(BASE_DIR, "files", "user_telegram.json") -PROMOCODES_FILE = os.path.join(BASE_DIR, "files", "promocodes.json") -PAYMENTS_FILE = os.path.join(BASE_DIR, "files", "payments.json") +CONFIG_FILE = 'files/config.json' +USER_EXPIRATION_FILE = 'files/user_expiration.json' +USER_TELEGRAM_FILE = 'files/user_telegram.json' +PROMOCODES_FILE = 'files/promocodes.json' def load_json(file_path, default=None): """Загружает JSON-файл, возвращает default при ошибке или отсутствии файла.""" @@ -39,94 +36,42 @@ def save_json(file_path, data): return False def get_config(): - """Возвращает конфигурацию из setting.ini.""" - config = configparser.ConfigParser() - 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 {} + """Возвращает конфигурацию из config.json.""" + return load_json(CONFIG_FILE, {}) def add_admin(admin_id): """Добавляет ID администратора в конфигурацию.""" config = get_config() - admin_ids = config.get('admin_ids', '').split(',') if config.get('admin_ids') else [] - admin_id_str = str(admin_id) - if admin_id_str not in admin_ids: - admin_ids.append(admin_id_str) - config['admin_ids'] = ','.join([aid for aid in admin_ids if aid]) - 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)}") + admin_ids = config.get('admin_ids', []) + if str(admin_id) not in admin_ids: + admin_ids.append(str(admin_id)) + config['admin_ids'] = admin_ids + save_json(CONFIG_FILE, config) def remove_admin(admin_id): """Удаляет ID администратора из конфигурации.""" 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 admin_id_str in admin_ids: admin_ids.remove(admin_id_str) - config['admin_ids'] = ','.join([aid for aid in admin_ids if aid]) - 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 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)}") + config['admin_ids'] = admin_ids + save_json(CONFIG_FILE, config) def set_pricing(period, price): """Устанавливает цену для указанного периода подписки.""" config = get_config() - pricing = config.get('pricing', {}) - pricing[period] = float(price) - config['pricing'] = json.dumps(pricing) # Сохраняем как JSON-строку - 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)}") + config['pricing'] = config.get('pricing', {}) + config['pricing'][period] = price + save_json(CONFIG_FILE, config) def root_add(name, ipv6=False): """Добавляет нового пользователя через newclient.sh.""" try: - cmd = [os.path.join(BASE_DIR, 'newclient.sh'), name] + cmd = ['./newclient.sh', name] if not 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: return True logger.error(f"Ошибка добавления пользователя {name}: {process.stderr}") @@ -138,7 +83,7 @@ def root_add(name, ipv6=False): def deactive_user_db(name): """Деактивирует пользователя через removeclient.sh.""" 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: return True logger.error(f"Ошибка удаления пользователя {name}: {process.stderr}") @@ -150,7 +95,7 @@ def deactive_user_db(name): def get_client_list(): """Возвращает список клиентов (имя и конфигурация).""" clients = [] - users_dir = os.path.join(BASE_DIR, 'users') + users_dir = 'users' if os.path.exists(users_dir): for user_dir in os.listdir(users_dir): user_path = os.path.join(users_dir, user_dir) @@ -165,16 +110,17 @@ def get_client_list(): def get_active_list(): """Возвращает список активных клиентов с последним handshake.""" active = [] - try: - result = subprocess.run(['wg', 'show', 'wg0', 'latest-handshakes'], capture_output=True, text=True) - lines = result.stdout.strip().split('\n') - for line in lines: - if line: - parts = line.split() - if len(parts) >= 2: - active.append((parts[0], datetime.fromtimestamp(int(parts[1])).strftime('%Y-%m-%d %H:%M:%S'))) - except Exception as e: - logger.error(f"Ошибка получения активных клиентов: {str(e)}") + users_dir = 'users' + if os.path.exists(users_dir): + for user_dir in os.listdir(users_dir): + user_path = os.path.join(users_dir, user_dir) + if os.path.isdir(user_path): + status_file = os.path.join(user_path, 'status.json') + if os.path.exists(status_file): + with open(status_file, 'r') as f: + status = json.load(f) + last_handshake = status.get('last_handshake', 'never') + active.append((user_dir, last_handshake)) return active 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: return False promocodes[code] = { - 'discount': float(discount), + 'discount': discount, 'expires_at': expires_at.isoformat() if expires_at else None, 'max_uses': max_uses, 'uses': 0, @@ -266,33 +212,3 @@ def remove_promocode(code): save_json(PROMOCODES_FILE, promocodes) return True 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' - ]