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:
| {{group}} |
{{status}} (открыта) |
% if group not in ['control', 'junk']:
% else:
системная
% end
|
% 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)