import os import re import subprocess from bottle import run, route, request, redirect, template # Простая HTML-страница со встроенными стилями HTML_TEMPLATE = """ NNTP (INN2) Web Panel

NNTP (INN2) Управление Сервером

% if msg:
{{msg}}
% end % if err:
{{err}}
% end

Создать новую группу / подгруппу

Активные группы на сервере

% for group, status in groups: % end
Имя группы Статус Действие
{{group}} {{status}} (открыта) % if group not in ['control', 'junk']:
% else: системная % end
""" def run_nntp_cmd(action, group_name=""): """Прямой и безопасный вызов ctlinnd через системный шелл, исключающий ошибки парсинга аргументов""" if action == "list": cmd = "sudo -u news ctlinnd list active" elif action == "create": cmd = f"sudo -u news ctlinnd newgroup {group_name} y" elif action == "delete": cmd = f"sudo -u news ctlinnd rmgroup {group_name}" else: return False, "Неверное действие" res = subprocess.run(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) if res.returncode == 0: return True, res.stdout else: return False, res.stderr if res.stderr else res.stdout def get_active_groups(): success, output = run_nntp_cmd("list") if not success: return [] parsed_groups = [] for line in output.strip().split("\n"): if not line: continue parts = line.split() if len(parts) >= 4: parsed_groups.append((parts[0], parts[3])) return parsed_groups @route('/') def index(): err = request.query.get('err', '') msg = request.query.get('msg', '') return template(HTML_TEMPLATE, groups=get_active_groups(), err=err, msg=msg) @route('/create', method='POST') def create(): group_name = request.forms.get('group_name', '').strip() if not group_name or not re.match(r"^[a-zA-Z0-9\.-]+$", group_name): return redirect('/?err=Invalid+group+name') success, out = run_nntp_cmd("create", group_name) if success: return redirect(f'/?msg=Group+{group_name}+created+successfully') else: return redirect(f'/?err={out.replace(" ", "+")}') @route('/delete', method='POST') def delete(): group_name = request.forms.get('group_name', '').strip() if group_name in ['control', 'junk']: return redirect('/?err=Cannot+delete+system+groups') success, out = run_nntp_cmd("delete", group_name) if success: return redirect(f'/?msg=Group+{group_name}+deleted') else: return redirect(f'/?err={out.replace(" ", "+")}') # Запуск веб-сервера на порту 8080 для всех IP адресов if __name__ == '__main__': run(host='0.0.0.0', port=8080, debug=True)