更新管理员登录和鉴权逻辑,优化用户体验;重构相关API以支持更安全的身份验证;调整数据库初始化以兼容新字段,确保用户信息安全;修复部分组件样式和功能,提升整体可用性。
This commit is contained in:
Binary file not shown.
155
scripts/deploy_baota_pure_api.py
Normal file
155
scripts/deploy_baota_pure_api.py
Normal file
@@ -0,0 +1,155 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
宝塔面板 API 模块 - Node 项目重启 / 计划任务触发
|
||||
|
||||
被 devlop.py 内部调用;也可单独使用:
|
||||
python scripts/deploy_baota_pure_api.py # 重启 Node 项目
|
||||
python scripts/deploy_baota_pure_api.py --create-dir # 并创建项目目录
|
||||
python scripts/deploy_baota_pure_api.py --task-id 1 # 触发计划任务 ID=1
|
||||
|
||||
环境变量:
|
||||
BAOTA_PANEL_URL # 宝塔面板地址,如 https://42.194.232.22:9988 或带安全入口
|
||||
BAOTA_API_KEY # 宝塔 API 密钥(面板 → 设置 → API 接口)
|
||||
DEPLOY_PM2_APP # PM2 项目名称,默认 soul
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import hashlib
|
||||
|
||||
try:
|
||||
import requests
|
||||
import urllib3
|
||||
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
|
||||
except ImportError:
|
||||
print("请先安装: pip install requests")
|
||||
sys.exit(1)
|
||||
|
||||
# 配置:可通过环境变量覆盖
|
||||
CFG = {
|
||||
"panel_url": os.environ.get("BAOTA_PANEL_URL", "https://42.194.232.22:9988"),
|
||||
"api_key": os.environ.get("BAOTA_API_KEY", "hsAWqFSi0GOCrunhmYdkxy92tBXfqYjd"),
|
||||
"pm2_name": os.environ.get("DEPLOY_PM2_APP", "soul"),
|
||||
"project_path": os.environ.get("DEPLOY_PROJECT_PATH", "/www/wwwroot/soul"),
|
||||
"site_url": os.environ.get("DEPLOY_SITE_URL", "https://soul.quwanzhi.com"),
|
||||
}
|
||||
|
||||
|
||||
def _get_sign(api_key):
|
||||
"""宝塔鉴权签名:request_token = md5(request_time + md5(api_key))"""
|
||||
now_time = int(time.time())
|
||||
sign_str = str(now_time) + hashlib.md5(api_key.encode("utf-8")).hexdigest()
|
||||
request_token = hashlib.md5(sign_str.encode("utf-8")).hexdigest()
|
||||
return now_time, request_token
|
||||
|
||||
|
||||
def _request(base_url, path, data=None, timeout=30):
|
||||
"""发起宝塔 API 请求"""
|
||||
url = base_url.rstrip("/") + "/" + path.lstrip("/")
|
||||
api_key = CFG["api_key"]
|
||||
if not api_key:
|
||||
print("请设置 BAOTA_API_KEY(宝塔面板 → 设置 → API 接口)")
|
||||
return None
|
||||
req_time, req_token = _get_sign(api_key)
|
||||
payload = {
|
||||
"request_time": req_time,
|
||||
"request_token": req_token,
|
||||
}
|
||||
if data:
|
||||
payload.update(data)
|
||||
try:
|
||||
r = requests.post(
|
||||
url,
|
||||
data=payload,
|
||||
verify=False,
|
||||
timeout=timeout,
|
||||
)
|
||||
return r.json() if r.text else None
|
||||
except Exception as e:
|
||||
print("请求失败:", e)
|
||||
return None
|
||||
|
||||
|
||||
def restart_node_project(panel_url, api_key, pm2_name):
|
||||
"""
|
||||
通过宝塔 API 重启 Node 项目
|
||||
返回 True 表示成功,False 表示失败
|
||||
"""
|
||||
# Node 项目管理为插件接口,路径可能因版本不同
|
||||
paths_to_try = [
|
||||
"/plugin?action=a&name=nodejs&s=restart_project",
|
||||
"/project/nodejs/restart_project",
|
||||
]
|
||||
payload = {"project_name": pm2_name}
|
||||
req_time, req_token = _get_sign(api_key)
|
||||
payload["request_time"] = req_time
|
||||
payload["request_token"] = req_token
|
||||
|
||||
url_base = panel_url.rstrip("/")
|
||||
for path in paths_to_try:
|
||||
url = url_base + path
|
||||
try:
|
||||
r = requests.post(url, data=payload, verify=False, timeout=30)
|
||||
j = r.json() if r.text else {}
|
||||
if j.get("status") is True or j.get("msg") or r.status_code == 200:
|
||||
print(" 重启成功: %s" % pm2_name)
|
||||
return True
|
||||
# 某些版本返回不同结构
|
||||
if "msg" in j:
|
||||
print(" API 返回:", j.get("msg", j))
|
||||
except Exception as e:
|
||||
print(" 尝试 %s 失败: %s" % (path, e))
|
||||
print(" 重启失败,请检查宝塔 Node 插件是否安装、API 密钥是否正确")
|
||||
return False
|
||||
|
||||
|
||||
def create_project_dir():
|
||||
"""通过宝塔文件接口创建项目目录"""
|
||||
path = "/files?action=CreateDir"
|
||||
data = {"path": CFG["project_path"]}
|
||||
j = _request(CFG["panel_url"], path, data)
|
||||
if j and j.get("status") is True:
|
||||
print(" 目录已创建: %s" % CFG["project_path"])
|
||||
return True
|
||||
print(" 创建目录失败:", j)
|
||||
return False
|
||||
|
||||
|
||||
def trigger_crontab_task(task_id):
|
||||
"""触发计划任务"""
|
||||
path = "/crontab?action=StartTask"
|
||||
data = {"id": str(task_id)}
|
||||
j = _request(CFG["panel_url"], path, data)
|
||||
if j and j.get("status") is True:
|
||||
print(" 计划任务 %s 已触发" % task_id)
|
||||
return True
|
||||
print(" 触发失败:", j)
|
||||
return False
|
||||
|
||||
|
||||
def main():
|
||||
import argparse
|
||||
parser = argparse.ArgumentParser(description="宝塔 API - 重启 Node / 触发计划任务")
|
||||
parser.add_argument("--create-dir", action="store_true", help="创建项目目录")
|
||||
parser.add_argument("--task-id", type=int, default=0, help="触发计划任务 ID")
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.create_dir:
|
||||
create_project_dir()
|
||||
if args.task_id:
|
||||
ok = trigger_crontab_task(args.task_id)
|
||||
sys.exit(0 if ok else 1)
|
||||
ok = restart_node_project(
|
||||
CFG["panel_url"],
|
||||
CFG["api_key"],
|
||||
CFG["pm2_name"],
|
||||
)
|
||||
sys.exit(0 if ok else 1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user