Files
abot/admin/dashboard/blueprints/group_plugin_config.py
T

128 lines
5.3 KiB
Python

# -*- coding: utf-8 -*-
import json
from datetime import datetime
from flask import Blueprint, current_app, jsonify, render_template, request
from .auth import login_required
group_plugin_config_bp = Blueprint("group_plugin_config", __name__, url_prefix="/group_plugin_config")
# 群级插件配置白名单:
# 当前业务阶段仅开放“群成员变更监控”,其余插件统一在后端拦截,
# 防止前端被绕过后写入不受控配置。
ALLOWED_PLUGIN_NAMES = {"群成员变更监控"}
def _normalize_datetime_text(value):
if value is None:
return value
if isinstance(value, datetime):
return value.strftime("%Y-%m-%d %H:%M:%S")
text = str(value)
if "T" in text:
return text.replace("T", " ")[:19]
return text
def _is_plugin_allowed(plugin_name: str) -> bool:
"""检查插件名是否在群级配置白名单内。"""
return str(plugin_name or "").strip() in ALLOWED_PLUGIN_NAMES
@group_plugin_config_bp.route("/")
@login_required
def page_group_plugin_config():
return render_template("group_plugin_config.html")
@group_plugin_config_bp.route("/api/list", methods=["GET"])
@login_required
def api_list_group_plugin_config():
server = current_app.dashboard_server
service = server.group_plugin_config_service
group_id = str(request.args.get("group_id", "") or "").strip()
plugin_name = str(request.args.get("plugin_name", "") or "").strip()
# 列表接口默认仅返回白名单插件,避免管理端仍出现其它插件配置。
# 若传入了非白名单插件名,直接返回空列表。
if plugin_name and not _is_plugin_allowed(plugin_name):
return jsonify({"success": True, "data": []})
if not plugin_name:
# service.list_configs 当前仅支持单个 plugin_name 过滤参数,
# 这里通过遍历白名单并聚合,确保结果严格受控。
rows = []
for allowed_name in sorted(ALLOWED_PLUGIN_NAMES):
rows.extend(service.list_configs(group_id=group_id, plugin_name=allowed_name))
else:
rows = service.list_configs(group_id=group_id, plugin_name=plugin_name)
for row in rows:
row["created_at"] = _normalize_datetime_text(row.get("created_at"))
row["updated_at"] = _normalize_datetime_text(row.get("updated_at"))
return jsonify({"success": True, "data": rows})
@group_plugin_config_bp.route("/api/plugins", methods=["GET"])
@login_required
def api_list_plugins():
# 插件下拉框只暴露白名单,前端无需自行过滤。
return jsonify({"success": True, "data": sorted(ALLOWED_PLUGIN_NAMES)})
@group_plugin_config_bp.route("/api/upsert", methods=["POST"])
@login_required
def api_upsert_group_plugin_config():
server = current_app.dashboard_server
service = server.group_plugin_config_service
payload = request.get_json(silent=True) or {}
group_id = str(payload.get("group_id") or "").strip()
plugin_name = str(payload.get("plugin_name") or "").strip()
config_key = str(payload.get("config_key") or "default").strip() or "default"
enabled = bool(payload.get("enabled", True))
config_data = payload.get("config_json")
updated_by = str(payload.get("updated_by") or "dashboard").strip() or "dashboard"
if not group_id or not plugin_name:
return jsonify({"success": False, "message": "group_id 或 plugin_name 不能为空"}), 400
if not _is_plugin_allowed(plugin_name):
return jsonify({"success": False, "message": f"当前仅允许配置:{','.join(sorted(ALLOWED_PLUGIN_NAMES))}"}), 400
if isinstance(config_data, str):
try:
config_data = json.loads(config_data)
except Exception:
return jsonify({"success": False, "message": "config_json 不是合法 JSON"}), 400
if not isinstance(config_data, dict):
return jsonify({"success": False, "message": "config_json 必须是对象"}), 400
ok = service.upsert_config(
group_id=group_id,
plugin_name=plugin_name,
config_key=config_key,
config_data=config_data,
enabled=enabled,
updated_by=updated_by,
)
if not ok:
return jsonify({"success": False, "message": "保存失败"}), 500
return jsonify({"success": True, "message": "保存成功(MySQL + Redis已刷新)"})
@group_plugin_config_bp.route("/api/delete", methods=["POST"])
@login_required
def api_delete_group_plugin_config():
server = current_app.dashboard_server
service = server.group_plugin_config_service
payload = request.get_json(silent=True) or {}
group_id = str(payload.get("group_id") or "").strip()
plugin_name = str(payload.get("plugin_name") or "").strip()
config_key = str(payload.get("config_key") or "default").strip() or "default"
if not group_id or not plugin_name:
return jsonify({"success": False, "message": "group_id 或 plugin_name 不能为空"}), 400
if not _is_plugin_allowed(plugin_name):
return jsonify({"success": False, "message": f"当前仅允许配置:{','.join(sorted(ALLOWED_PLUGIN_NAMES))}"}), 400
ok = service.delete_config(group_id=group_id, plugin_name=plugin_name, config_key=config_key)
if not ok:
return jsonify({"success": False, "message": "删除失败"}), 500
return jsonify({"success": True, "message": "删除成功(MySQL + Redis已同步)"})