refactor: CMS从Sage子模块重构为独立ahserver Web应用
架构变更: - CMS作为独立进程运行(端口9090),不再嵌入Sage - 使用ahserver框架,复用rbac模块做认证授权 - 所有模块共享sage数据库(配置在conf/config.json) 新增文件: - app/cms.py: 独立Web应用主入口(webapp(init)) - app/global_func.py: 全局函数(get_module_dbname/UiWindow等) - conf/config.json: 应用配置模板(数据库/路径/处理器/Redis) - start.sh/stop.sh: 进程管理脚本 - pyproject.toml: 顶层Python包配置 路径重构(去掉/entcms前缀): - 官网首页: /entcms/index.ui → /index.ui - 管理后台: /entcms/admin.ui → /admin.ui - API: /entcms/api/xxx.dspy → /api/xxx.dspy - CRUD: /entcms/cms_content_list → /cms_content_list - dingdingflow保持/dingdingflow前缀(映射子目录) config.json路径映射: - entcms/wwwroot → / (根路径) - dingdingflow/wwwroot → /dingdingflow - bricks/dist → /bricks 构建脚本(build.sh): - 创建独立venv(py3/) - 安装核心依赖(apppublic/sqlor/ahserver/bricks/rbac等) - json2ddl生成CMS业务表DDL - xls2ui生成CRUD UI - 生成systemd服务文件 load_path.py更新: - entcms: 所有路径去掉/entcms前缀 - dingdingflow: 保持/dingdingflow前缀 - 查找set_role_perm.py支持CMS和Sage两种环境 init_superuser.py更新: - 支持CMS独立环境(自动检测py3/conf) - 创建superuser角色并分配全部权限
This commit is contained in:
parent
52f4632dfc
commit
569c8e6715
32
.gitignore
vendored
32
.gitignore
vendored
@ -1,3 +1,31 @@
|
||||
*.pyc
|
||||
# Python
|
||||
__pycache__/
|
||||
mysql.ddl.sql
|
||||
*.py[cod]
|
||||
*.egg-info/
|
||||
dist/
|
||||
build/
|
||||
|
||||
# Virtual environment
|
||||
py3/
|
||||
pkgs/
|
||||
|
||||
# Runtime
|
||||
logs/
|
||||
files/
|
||||
*.pid
|
||||
cms.service
|
||||
|
||||
# DDL generated
|
||||
*/mysql.ddl.sql
|
||||
|
||||
# IDE
|
||||
.idea/
|
||||
.vscode/
|
||||
*.swp
|
||||
|
||||
# OS
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
# Config with credentials
|
||||
# conf/config.json # Keep template in git
|
||||
|
||||
42
app/cms.py
Normal file
42
app/cms.py
Normal file
@ -0,0 +1,42 @@
|
||||
"""
|
||||
开元云科技CMS — 独立Web应用主入口
|
||||
启动: py3/bin/python app/cms.py -p 9090 -w $(pwd)
|
||||
"""
|
||||
import os, sys
|
||||
|
||||
# Ensure app/ is in path for local imports
|
||||
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
||||
|
||||
from appPublic.log import MyLogger, info
|
||||
from appPublic.folderUtils import ProgramPath
|
||||
from appPublic.jsonConfig import getConfig
|
||||
from appPublic.registerfunction import RegisterFunction
|
||||
from bricks_for_python.init import load_pybricks
|
||||
from ahserver.webapp import webapp
|
||||
from ahserver.serverenv import ServerEnv
|
||||
from sqlor.dbpools import DBPools
|
||||
|
||||
# CMS业务模块
|
||||
from entcms.init import load_entcms
|
||||
from dingdingflow.init import load_dingdingflow
|
||||
|
||||
# RBAC认证(复用sage的rbac模块)
|
||||
from rbac.init import load_rbac
|
||||
from appbase.init import load_appbase
|
||||
|
||||
# 全局函数
|
||||
from global_func import set_globalvariable
|
||||
|
||||
__version__ = '1.0.0'
|
||||
|
||||
def init():
|
||||
rf = RegisterFunction()
|
||||
set_globalvariable()
|
||||
load_pybricks()
|
||||
load_appbase()
|
||||
load_rbac()
|
||||
load_entcms()
|
||||
load_dingdingflow()
|
||||
|
||||
if __name__ == '__main__':
|
||||
webapp(init)
|
||||
56
app/global_func.py
Normal file
56
app/global_func.py
Normal file
@ -0,0 +1,56 @@
|
||||
"""
|
||||
CMS全局函数 — 注册到ServerEnv供.dspy和.ui调用
|
||||
"""
|
||||
from ahserver.serverenv import ServerEnv
|
||||
|
||||
def get_module_dbname(mname):
|
||||
"""所有模块共享sage数据库"""
|
||||
return 'sage'
|
||||
|
||||
def UiWindow(title, icon, content, cheight=10, cwidth=15):
|
||||
return {
|
||||
"widgettype": "PopupWindow",
|
||||
"options": {
|
||||
"author": "cms",
|
||||
"cwidth": cwidth,
|
||||
"cheight": cheight,
|
||||
"title": title,
|
||||
"content": content,
|
||||
"icon": icon or entire_url('/bricks/imgs/app.png'),
|
||||
"movable": True,
|
||||
"auto_open": True
|
||||
}
|
||||
}
|
||||
|
||||
def UiError(title="出错", message="出错啦", timeout=5):
|
||||
return {
|
||||
"widgettype": "Error",
|
||||
"options": {
|
||||
"author": "cms",
|
||||
"timeout": timeout,
|
||||
"cwidth": 15,
|
||||
"cheight": 10,
|
||||
"title": title,
|
||||
"message": message
|
||||
}
|
||||
}
|
||||
|
||||
def UiMessage(title="消息", message="后台消息", timeout=5):
|
||||
return {
|
||||
"widgettype": "Message",
|
||||
"options": {
|
||||
"author": "cms",
|
||||
"timeout": timeout,
|
||||
"cwidth": 15,
|
||||
"cheight": 10,
|
||||
"title": title,
|
||||
"message": message
|
||||
}
|
||||
}
|
||||
|
||||
def set_globalvariable():
|
||||
g = ServerEnv()
|
||||
g.get_module_dbname = get_module_dbname
|
||||
g.UiError = UiError
|
||||
g.UiMessage = UiMessage
|
||||
g.UiWindow = UiWindow
|
||||
261
build.sh
261
build.sh
@ -1,87 +1,198 @@
|
||||
#!/bin/bash
|
||||
# CMS项目构建脚本
|
||||
# 构建 entcms + dingdingflow 模块并集成到Sage系统
|
||||
|
||||
#!/usr/bin/env bash
|
||||
# 开元云科技CMS — 独立Web应用构建脚本
|
||||
# 用法: cd ~/repos/cms && ./build.sh
|
||||
set -e
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
echo "=== CMS项目构建 ==="
|
||||
echo "Script dir: $SCRIPT_DIR"
|
||||
cdir=$(pwd)
|
||||
uname=$(id -un)
|
||||
gname=$(id -gn)
|
||||
|
||||
# 查找Sage根目录
|
||||
SAGE_ROOT=""
|
||||
for candidate in "$SCRIPT_DIR/../.." "$HOME/repos/sage" "$HOME/sage"; do
|
||||
if [ -d "$candidate/wwwroot" ] && [ -d "$candidate/py3/bin" ]; then
|
||||
SAGE_ROOT="$(cd "$candidate" && pwd)"
|
||||
break
|
||||
echo "============================================"
|
||||
echo " 开元云科技CMS — 独立Web应用构建"
|
||||
echo "============================================"
|
||||
|
||||
# ===========================================
|
||||
# Step 1: Python虚拟环境
|
||||
# ===========================================
|
||||
echo ""
|
||||
echo "--- Step 1: 创建Python虚拟环境 ---"
|
||||
if [ ! -d "py3" ]; then
|
||||
python3 -m venv py3
|
||||
fi
|
||||
source py3/bin/activate
|
||||
|
||||
# ===========================================
|
||||
# Step 2: 核心依赖
|
||||
# ===========================================
|
||||
echo ""
|
||||
echo "--- Step 2: 安装核心依赖 ---"
|
||||
mkdir -p pkgs
|
||||
|
||||
# 核心框架包
|
||||
for m in apppublic sqlor ahserver bricks-for-python xls2ddl
|
||||
do
|
||||
echo " install $m..."
|
||||
cd $cdir/pkgs
|
||||
if [ ! -d "$m" ]; then
|
||||
git clone https://git.opencomputing.cn/yumoqing/$m
|
||||
fi
|
||||
cd $m
|
||||
$cdir/py3/bin/pip install . 2>/dev/null || echo " WARN: $m install failed"
|
||||
done
|
||||
|
||||
if [ -z "$SAGE_ROOT" ]; then
|
||||
echo "ERROR: 找不到Sage根目录"
|
||||
exit 1
|
||||
# bricks前端
|
||||
echo " install bricks..."
|
||||
cd $cdir/pkgs
|
||||
if [ ! -d "bricks" ]; then
|
||||
git clone https://git.opencomputing.cn/yumoqing/bricks
|
||||
fi
|
||||
cd bricks/bricks
|
||||
./build.sh 2>/dev/null || echo " WARN: bricks build skipped"
|
||||
|
||||
# bricks符号链接
|
||||
mkdir -p $cdir/bricks
|
||||
if [ -d "$cdir/pkgs/bricks/dist" ]; then
|
||||
rm -f $cdir/bricks
|
||||
ln -sf $cdir/pkgs/bricks/dist $cdir/bricks
|
||||
fi
|
||||
|
||||
echo "Sage root: $SAGE_ROOT"
|
||||
PY="$SAGE_ROOT/py3/bin/python"
|
||||
PIP="$SAGE_ROOT/py3/bin/pip"
|
||||
|
||||
# 安装模块
|
||||
for mod in entcms dingdingflow; do
|
||||
echo ""
|
||||
echo "=== 安装 $mod ==="
|
||||
cd "$SCRIPT_DIR/$mod"
|
||||
$PIP install -e .
|
||||
|
||||
# 生成DDL
|
||||
if [ -d "models" ] && [ "$(ls models/*.json 2>/dev/null)" ]; then
|
||||
echo "生成DDL..."
|
||||
cd models
|
||||
$PY -c "from sqlor.ddl_template_mysql import DDLTemplate; print(DDLTemplate().generate('.'))" > ../mysql.ddl.sql 2>/dev/null || json2ddl mysql . > ../mysql.ddl.sql 2>/dev/null || echo "DDL generation skipped (json2ddl not available)"
|
||||
cd ..
|
||||
# ===========================================
|
||||
# Step 3: RBAC + AppBase模块(认证依赖)
|
||||
# ===========================================
|
||||
echo ""
|
||||
echo "--- Step 3: 安装RBAC/AppBase模块 ---"
|
||||
for m in appbase rbac checklang
|
||||
do
|
||||
echo " install $m..."
|
||||
cd $cdir/pkgs
|
||||
if [ ! -d "$m" ]; then
|
||||
git clone https://git.opencomputing.cn/yumoqing/$m
|
||||
fi
|
||||
|
||||
# 生成CRUD UI
|
||||
if [ -d "json" ] && [ "$(ls json/*.json 2>/dev/null)" ]; then
|
||||
echo "生成CRUD UI..."
|
||||
cd json
|
||||
xls2ui -m ../models -o ../wwwroot $mod *.json 2>/dev/null || echo "CRUD UI generation skipped (xls2ui not available)"
|
||||
cd ..
|
||||
fi
|
||||
|
||||
# 链接wwwroot到Sage
|
||||
MODULE_WWWROOT="$SAGE_ROOT/wwwroot/$mod"
|
||||
mkdir -p "$MODULE_WWWROOT/api"
|
||||
|
||||
# 链接UI/CSS/JS文件
|
||||
for f in "$SCRIPT_DIR/$mod/wwwroot"/*.ui "$SCRIPT_DIR/$mod/wwwroot"/*.css "$SCRIPT_DIR/$mod/wwwroot"/*.js; do
|
||||
[ -f "$f" ] || continue
|
||||
fname=$(basename "$f")
|
||||
ln -sf "$f" "$MODULE_WWWROOT/$fname"
|
||||
done
|
||||
|
||||
# 链接api目录下的.dspy文件
|
||||
for f in "$SCRIPT_DIR/$mod/wwwroot/api"/*.dspy; do
|
||||
[ -f "$f" ] || continue
|
||||
fname=$(basename "$f")
|
||||
ln -sf "$f" "$MODULE_WWWROOT/api/$fname"
|
||||
done
|
||||
|
||||
# 链接生成的CRUD目录
|
||||
for d in "$SCRIPT_DIR/$mod/wwwroot"/*/; do
|
||||
[ -d "$d" ] || continue
|
||||
dname=$(basename "$d")
|
||||
case "$dname" in api|styles|scripts) continue ;; esac
|
||||
ln -sf "$d" "$MODULE_WWWROOT/$dname"
|
||||
done
|
||||
|
||||
echo "$mod 安装完成"
|
||||
cd $m
|
||||
$cdir/py3/bin/pip install . 2>/dev/null || echo " WARN: $m install failed"
|
||||
done
|
||||
|
||||
# ===========================================
|
||||
# Step 4: CMS业务模块
|
||||
# ===========================================
|
||||
echo ""
|
||||
echo "=== 构建完成 ==="
|
||||
echo "请执行以下步骤完成集成:"
|
||||
echo "1. 编辑 $SAGE_ROOT/app/sage.py 添加模块导入"
|
||||
echo "2. 编辑 $SAGE_ROOT/build.sh 添加模块到安装循环"
|
||||
echo "3. 执行 RBAC 权限配置"
|
||||
echo "4. 重启Sage服务"
|
||||
echo "--- Step 4: 安装CMS业务模块 ---"
|
||||
|
||||
# entcms模块
|
||||
echo " install entcms..."
|
||||
cd $cdir/entcms
|
||||
$cdir/py3/bin/pip install . 2>/dev/null || echo " WARN: entcms install failed"
|
||||
|
||||
# dingdingflow模块
|
||||
echo " install dingdingflow..."
|
||||
cd $cdir/dingdingflow
|
||||
$cdir/py3/bin/pip install . 2>/dev/null || echo " WARN: dingdingflow install failed"
|
||||
|
||||
# ===========================================
|
||||
# Step 5: 数据库DDL(CMS业务表)
|
||||
# ===========================================
|
||||
echo ""
|
||||
echo "--- Step 5: 生成数据库DDL ---"
|
||||
|
||||
# entcms表DDL
|
||||
if [ -d "$cdir/entcms/models" ]; then
|
||||
cd $cdir/entcms/models
|
||||
echo " 生成 entcms DDL..."
|
||||
$cdir/py3/bin/json2ddl mysql . > $cdir/entcms/mysql.ddl.sql 2>/dev/null || echo " WARN: json2ddl failed for entcms"
|
||||
echo " DDL已生成: entcms/mysql.ddl.sql"
|
||||
fi
|
||||
|
||||
# dingdingflow表DDL
|
||||
if [ -d "$cdir/dingdingflow/models" ]; then
|
||||
cd $cdir/dingdingflow/models
|
||||
echo " 生成 dingdingflow DDL..."
|
||||
$cdir/py3/bin/json2ddl mysql . > $cdir/dingdingflow/mysql.ddl.sql 2>/dev/null || echo " WARN: json2ddl failed for dingdingflow"
|
||||
echo " DDL已生成: dingdingflow/mysql.ddl.sql"
|
||||
fi
|
||||
|
||||
# ===========================================
|
||||
# Step 6: CRUD UI生成
|
||||
# ===========================================
|
||||
echo ""
|
||||
echo "--- Step 6: 生成CRUD UI ---"
|
||||
|
||||
# entcms CRUD
|
||||
if [ -d "$cdir/entcms/json" ]; then
|
||||
cd $cdir/entcms/json
|
||||
echo " 生成 entcms CRUD UI..."
|
||||
for f in *.json; do
|
||||
[ -f "$f" ] || continue
|
||||
echo " $f"
|
||||
$cdir/py3/bin/xls2ui -m ../models -o ../wwwroot entcms $f 2>/dev/null || echo " WARN: xls2ui failed for $f"
|
||||
done
|
||||
fi
|
||||
|
||||
# dingdingflow CRUD
|
||||
if [ -d "$cdir/dingdingflow/json" ]; then
|
||||
cd $cdir/dingdingflow/json
|
||||
echo " 生成 dingdingflow CRUD UI..."
|
||||
for f in *.json; do
|
||||
[ -f "$f" ] || continue
|
||||
echo " $f"
|
||||
$cdir/py3/bin/xls2ui -m ../models -o ../wwwroot dingdingflow $f 2>/dev/null || echo " WARN: xls2ui failed for $f"
|
||||
done
|
||||
fi
|
||||
|
||||
# ===========================================
|
||||
# Step 7: 日志和文件目录
|
||||
# ===========================================
|
||||
echo ""
|
||||
echo "--- Step 7: 创建运行时目录 ---"
|
||||
mkdir -p $cdir/logs
|
||||
mkdir -p $cdir/files
|
||||
|
||||
# ===========================================
|
||||
# Step 8: systemd服务文件
|
||||
# ===========================================
|
||||
echo ""
|
||||
echo "--- Step 8: 生成systemd服务文件 ---"
|
||||
cat > $cdir/cms.service <<EOF
|
||||
[Unit]
|
||||
Description=KaiYuan Cloud CMS Web Application
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
User=$uname
|
||||
Group=$gname
|
||||
Type=forking
|
||||
WorkingDirectory=$cdir
|
||||
ExecStart=$cdir/start.sh
|
||||
ExecStop=$cdir/stop.sh
|
||||
StandardOutput=append:$cdir/logs/cms.log
|
||||
StandardError=append:$cdir/logs/cms.log
|
||||
SyslogIdentifier=cms
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
echo " cms.service 已生成"
|
||||
|
||||
# ===========================================
|
||||
# Done
|
||||
# ===========================================
|
||||
cd $cdir
|
||||
echo ""
|
||||
echo "============================================"
|
||||
echo " 构建完成!"
|
||||
echo "============================================"
|
||||
echo ""
|
||||
echo "后续步骤:"
|
||||
echo " 1. 编辑 conf/config.json 填入数据库密码"
|
||||
echo " 2. 执行DDL创建CMS业务表:"
|
||||
echo " mysql -h HOST -u USER -pPASS sage < entcms/mysql.ddl.sql"
|
||||
echo " mysql -h HOST -u USER -pPASS sage < dingdingflow/mysql.ddl.sql"
|
||||
echo " 3. 加载RBAC权限:"
|
||||
echo " py3/bin/python entcms/scripts/load_path.py"
|
||||
echo " py3/bin/python dingdingflow/scripts/load_path.py"
|
||||
echo " 4. 初始化超级用户:"
|
||||
echo " py3/bin/python scripts/init_superuser.py"
|
||||
echo " 5. 启动应用:"
|
||||
echo " ./start.sh"
|
||||
echo ""
|
||||
echo "访问地址: http://localhost:9090/"
|
||||
echo "管理后台: http://localhost:9090/admin.ui"
|
||||
|
||||
80
conf/config.json
Normal file
80
conf/config.json
Normal file
@ -0,0 +1,80 @@
|
||||
{
|
||||
"password_key": "CHANGE_ME_16_CHARS",
|
||||
"logger": {
|
||||
"name": "cms",
|
||||
"levelname": "info",
|
||||
"logfile": "$[workdir]$/logs/cms.log"
|
||||
},
|
||||
"filesroot": "$[workdir]$/files",
|
||||
"databases": {
|
||||
"sage": {
|
||||
"driver": "aiomysql",
|
||||
"async_mode": true,
|
||||
"coding": "utf8",
|
||||
"dbname": "sage",
|
||||
"kwargs": {
|
||||
"user": "test",
|
||||
"db": "sage",
|
||||
"password": "ENCRYPTED_PASSWORD_HERE",
|
||||
"host": "localhost"
|
||||
}
|
||||
}
|
||||
},
|
||||
"website": {
|
||||
"paths": [
|
||||
[
|
||||
"$[workdir]$/entcms/wwwroot",
|
||||
""
|
||||
],
|
||||
[
|
||||
"$[workdir]$/dingdingflow/wwwroot",
|
||||
"/dingdingflow"
|
||||
],
|
||||
[
|
||||
"$[workdir]$/bricks",
|
||||
"/bricks"
|
||||
]
|
||||
],
|
||||
"host": "0.0.0.0",
|
||||
"port": 9090,
|
||||
"coding": "utf-8",
|
||||
"session_redis": {
|
||||
"url": "redis://127.0.0.1:6379/0"
|
||||
},
|
||||
"indexes": [
|
||||
"index.ui",
|
||||
"index.html",
|
||||
"index.tmpl"
|
||||
],
|
||||
"processors": [
|
||||
[
|
||||
".xlsxds",
|
||||
"xlsxds"
|
||||
],
|
||||
[
|
||||
".sqlds",
|
||||
"sqlds"
|
||||
],
|
||||
[
|
||||
".tmpl",
|
||||
"tmpl"
|
||||
],
|
||||
[
|
||||
".dspy",
|
||||
"dspy"
|
||||
],
|
||||
[
|
||||
".ui",
|
||||
"bui"
|
||||
],
|
||||
[
|
||||
".md",
|
||||
"md"
|
||||
]
|
||||
]
|
||||
},
|
||||
"langMapping": {
|
||||
"zh-Hans-CN": "zh-cn",
|
||||
"en-US": "en"
|
||||
}
|
||||
}
|
||||
@ -1,24 +1,28 @@
|
||||
"""
|
||||
dingdingflow RBAC权限配置 — 企业类型: owner
|
||||
角色: superuser(继承全部), webmaster(提交审批), reviewer(审批管理),
|
||||
supervisor(审批配置)
|
||||
CMS独立部署,dingdingflow路径保持/dingdingflow前缀
|
||||
|
||||
用法: cd ~/repos/sage && ./py3/bin/python ~/repos/cms/dingdingflow/scripts/load_path.py
|
||||
用法: cd ~/repos/cms && py3/bin/python dingdingflow/scripts/load_path.py
|
||||
"""
|
||||
import os, sys, subprocess
|
||||
|
||||
def find_sage_root():
|
||||
for c in [os.path.expanduser("~/repos/sage"), os.path.expanduser("~/sage")]:
|
||||
if os.path.isdir(os.path.join(c, "wwwroot")) and os.path.isdir(os.path.join(c, "py3")):
|
||||
return c
|
||||
return None
|
||||
def find_app_root():
|
||||
script_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
return os.path.dirname(os.path.dirname(script_dir))
|
||||
|
||||
sage_root = find_sage_root()
|
||||
app_root = find_app_root()
|
||||
sage_root = None
|
||||
for c in [os.path.expanduser("~/repos/sage"), os.path.expanduser("~/sage")]:
|
||||
if os.path.isdir(os.path.join(c, "py3", "bin")):
|
||||
sage_root = c
|
||||
break
|
||||
if not sage_root:
|
||||
print("ERROR: Cannot find Sage root"); sys.exit(1)
|
||||
sage_root = app_root
|
||||
|
||||
py = os.path.join(sage_root, "py3", "bin", "python")
|
||||
sp = os.path.join(sage_root, "set_role_perm.py")
|
||||
py = os.path.join(app_root, "py3", "bin", "python")
|
||||
sp = os.path.join(sage_root, "set_role_perm.py") if os.path.exists(os.path.join(sage_root, "set_role_perm.py")) else None
|
||||
if not sp:
|
||||
print("ERROR: 找不到set_role_perm.py"); sys.exit(1)
|
||||
|
||||
def run(role, paths):
|
||||
for p in paths:
|
||||
@ -30,7 +34,6 @@ any_paths = [
|
||||
"/dingdingflow/menu.ui",
|
||||
]
|
||||
|
||||
# webmaster: 提交审批
|
||||
webmaster_paths = [
|
||||
"/dingdingflow",
|
||||
"/dingdingflow/index.ui",
|
||||
@ -39,7 +42,6 @@ webmaster_paths = [
|
||||
"/dingdingflow/api/dd_approvals_list.dspy",
|
||||
]
|
||||
|
||||
# reviewer: 审批管理(查看全部 + 更新审批状态)
|
||||
reviewer_paths = [
|
||||
"/dingdingflow",
|
||||
"/dingdingflow/index.ui",
|
||||
@ -48,7 +50,6 @@ reviewer_paths = [
|
||||
"/dingdingflow/api/dd_approvals_update.dspy",
|
||||
]
|
||||
|
||||
# supervisor: 审批配置管理 + 全部审批记录
|
||||
supervisor_paths = [
|
||||
"/dingdingflow",
|
||||
"/dingdingflow/index.ui",
|
||||
@ -66,12 +67,8 @@ supervisor_paths = [
|
||||
]
|
||||
|
||||
print("=== dingdingflow RBAC权限配置 ===")
|
||||
print(f"\n--- any (匿名/钉钉回调) ---")
|
||||
run("any", any_paths)
|
||||
print(f"\n--- owner.webmaster ---")
|
||||
run("owner.webmaster", webmaster_paths)
|
||||
print(f"\n--- owner.reviewer ---")
|
||||
run("owner.reviewer", reviewer_paths)
|
||||
print(f"\n--- owner.supervisor ---")
|
||||
run("owner.supervisor", supervisor_paths)
|
||||
print("\n完成")
|
||||
|
||||
@ -29,9 +29,9 @@
|
||||
}
|
||||
},
|
||||
"editable": {
|
||||
"new_data_url": "{{entire_url('../api/cms_categories_create.dspy')}}",
|
||||
"update_data_url": "{{entire_url('../api/cms_categories_update.dspy')}}",
|
||||
"delete_data_url": "{{entire_url('../api/cms_categories_delete.dspy')}}"
|
||||
"new_data_url": "{{entire_url('api/cms_categories_create.dspy')}}",
|
||||
"update_data_url": "{{entire_url('api/cms_categories_update.dspy')}}",
|
||||
"delete_data_url": "{{entire_url('api/cms_categories_delete.dspy')}}"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -89,9 +89,9 @@
|
||||
}
|
||||
},
|
||||
"editable": {
|
||||
"new_data_url": "{{entire_url('../api/cms_content_create.dspy')}}",
|
||||
"update_data_url": "{{entire_url('../api/cms_content_update.dspy')}}",
|
||||
"delete_data_url": "{{entire_url('../api/cms_content_delete.dspy')}}"
|
||||
"new_data_url": "{{entire_url('api/cms_content_create.dspy')}}",
|
||||
"update_data_url": "{{entire_url('api/cms_content_update.dspy')}}",
|
||||
"delete_data_url": "{{entire_url('api/cms_content_delete.dspy')}}"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -85,9 +85,9 @@
|
||||
}
|
||||
},
|
||||
"editable": {
|
||||
"new_data_url": "{{entire_url('../api/cms_leads_create.dspy')}}",
|
||||
"update_data_url": "{{entire_url('../api/cms_leads_update.dspy')}}",
|
||||
"delete_data_url": "{{entire_url('../api/cms_leads_delete.dspy')}}"
|
||||
"new_data_url": "{{entire_url('api/cms_leads_create.dspy')}}",
|
||||
"update_data_url": "{{entire_url('api/cms_leads_update.dspy')}}",
|
||||
"delete_data_url": "{{entire_url('api/cms_leads_delete.dspy')}}"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -84,9 +84,9 @@
|
||||
}
|
||||
},
|
||||
"editable": {
|
||||
"new_data_url": "{{entire_url('../api/cms_sections_create.dspy')}}",
|
||||
"update_data_url": "{{entire_url('../api/cms_sections_update.dspy')}}",
|
||||
"delete_data_url": "{{entire_url('../api/cms_sections_delete.dspy')}}"
|
||||
"new_data_url": "{{entire_url('api/cms_sections_create.dspy')}}",
|
||||
"update_data_url": "{{entire_url('api/cms_sections_update.dspy')}}",
|
||||
"delete_data_url": "{{entire_url('api/cms_sections_delete.dspy')}}"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -55,9 +55,9 @@
|
||||
}
|
||||
},
|
||||
"editable": {
|
||||
"new_data_url": "{{entire_url('../api/cms_site_config_create.dspy')}}",
|
||||
"update_data_url": "{{entire_url('../api/cms_site_config_update.dspy')}}",
|
||||
"delete_data_url": "{{entire_url('../api/cms_site_config_delete.dspy')}}"
|
||||
"new_data_url": "{{entire_url('api/cms_site_config_create.dspy')}}",
|
||||
"update_data_url": "{{entire_url('api/cms_site_config_update.dspy')}}",
|
||||
"delete_data_url": "{{entire_url('api/cms_site_config_delete.dspy')}}"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,25 +1,34 @@
|
||||
"""
|
||||
entcms RBAC权限配置 — 企业类型: owner
|
||||
角色: superuser(继承全部), webmaster(内容管理), reviewer(审核),
|
||||
supervisor(主管), customer-support(客服)
|
||||
匿名: any (公开页面)
|
||||
CMS独立部署,路径不带/entcms前缀
|
||||
|
||||
用法: cd ~/repos/sage && ./py3/bin/python ~/repos/cms/entcms/scripts/load_path.py
|
||||
用法: cd ~/repos/cms && py3/bin/python entcms/scripts/load_path.py
|
||||
"""
|
||||
import os, sys, subprocess
|
||||
|
||||
def find_sage_root():
|
||||
for c in [os.path.expanduser("~/repos/sage"), os.path.expanduser("~/sage")]:
|
||||
if os.path.isdir(os.path.join(c, "wwwroot")) and os.path.isdir(os.path.join(c, "py3")):
|
||||
return c
|
||||
return None
|
||||
def find_app_root():
|
||||
"""查找CMS应用根目录"""
|
||||
script_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
# scripts/ -> entcms/ -> cms root
|
||||
return os.path.dirname(os.path.dirname(script_dir))
|
||||
|
||||
sage_root = find_sage_root()
|
||||
app_root = find_app_root()
|
||||
# 查找Sage的set_role_perm.py(RBAC工具)
|
||||
sage_root = None
|
||||
for c in [os.path.expanduser("~/repos/sage"), os.path.expanduser("~/sage")]:
|
||||
if os.path.isdir(os.path.join(c, "py3", "bin")):
|
||||
sage_root = c
|
||||
break
|
||||
if not sage_root:
|
||||
print("ERROR: Cannot find Sage root"); sys.exit(1)
|
||||
# 使用CMS自己的py3
|
||||
sage_root = app_root
|
||||
|
||||
py = os.path.join(sage_root, "py3", "bin", "python")
|
||||
sp = os.path.join(sage_root, "set_role_perm.py")
|
||||
py = os.path.join(app_root, "py3", "bin", "python")
|
||||
sp = os.path.join(sage_root, "set_role_perm.py") if os.path.exists(os.path.join(sage_root, "set_role_perm.py")) else None
|
||||
|
||||
if not sp:
|
||||
print("ERROR: 找不到set_role_perm.py,请确保Sage或CMS已构建")
|
||||
sys.exit(1)
|
||||
|
||||
def run(role, paths):
|
||||
for p in paths:
|
||||
@ -28,105 +37,97 @@ def run(role, paths):
|
||||
|
||||
# ─── anonymous (any) — 公开页面 + 公开API ───
|
||||
any_paths = [
|
||||
"/entcms/index.ui",
|
||||
"/entcms/news.ui",
|
||||
"/entcms/news_detail.ui",
|
||||
"/entcms/cases.ui",
|
||||
"/entcms/products.ui",
|
||||
"/entcms/cms_styles.css",
|
||||
"/entcms/cms_scripts.js",
|
||||
"/entcms/menu.ui",
|
||||
"/entcms/api/submit_lead.dspy",
|
||||
"/entcms/api/get_config.dspy",
|
||||
"/entcms/api/get_published_content.dspy",
|
||||
"/entcms/api/get_content_detail.dspy",
|
||||
"/entcms/api/get_sections.dspy",
|
||||
"/index.ui",
|
||||
"/news.ui",
|
||||
"/news_detail.ui",
|
||||
"/cases.ui",
|
||||
"/products.ui",
|
||||
"/cms_styles.css",
|
||||
"/cms_scripts.js",
|
||||
"/menu.ui",
|
||||
"/api/submit_lead.dspy",
|
||||
"/api/get_config.dspy",
|
||||
"/api/get_published_content.dspy",
|
||||
"/api/get_content_detail.dspy",
|
||||
"/api/get_sections.dspy",
|
||||
]
|
||||
|
||||
# ─── webmaster — 内容/分类/栏目/配置/线索 全部CRUD ───
|
||||
webmaster_paths = [
|
||||
"/entcms",
|
||||
"/entcms/admin.ui",
|
||||
"/admin.ui",
|
||||
# 内容
|
||||
"/entcms/cms_content_list", "/entcms/cms_content_list/%",
|
||||
"/entcms/api/cms_content_create.dspy",
|
||||
"/entcms/api/cms_content_update.dspy",
|
||||
"/entcms/api/cms_content_delete.dspy",
|
||||
"/entcms/api/cms_content_list.dspy",
|
||||
"/cms_content_list", "/cms_content_list/%",
|
||||
"/api/cms_content_create.dspy",
|
||||
"/api/cms_content_update.dspy",
|
||||
"/api/cms_content_delete.dspy",
|
||||
"/api/cms_content_list.dspy",
|
||||
# 分类
|
||||
"/entcms/cms_categories_list", "/entcms/cms_categories_list/%",
|
||||
"/entcms/api/cms_categories_create.dspy",
|
||||
"/entcms/api/cms_categories_update.dspy",
|
||||
"/entcms/api/cms_categories_delete.dspy",
|
||||
"/entcms/api/cms_categories_list.dspy",
|
||||
"/entcms/api/category_options.dspy",
|
||||
"/cms_categories_list", "/cms_categories_list/%",
|
||||
"/api/cms_categories_create.dspy",
|
||||
"/api/cms_categories_update.dspy",
|
||||
"/api/cms_categories_delete.dspy",
|
||||
"/api/cms_categories_list.dspy",
|
||||
"/api/category_options.dspy",
|
||||
# 栏目
|
||||
"/entcms/cms_sections_list", "/entcms/cms_sections_list/%",
|
||||
"/entcms/api/cms_sections_create.dspy",
|
||||
"/entcms/api/cms_sections_update.dspy",
|
||||
"/entcms/api/cms_sections_delete.dspy",
|
||||
"/entcms/api/cms_sections_list.dspy",
|
||||
"/cms_sections_list", "/cms_sections_list/%",
|
||||
"/api/cms_sections_create.dspy",
|
||||
"/api/cms_sections_update.dspy",
|
||||
"/api/cms_sections_delete.dspy",
|
||||
"/api/cms_sections_list.dspy",
|
||||
# 站点配置
|
||||
"/entcms/cms_site_config_list", "/entcms/cms_site_config_list/%",
|
||||
"/entcms/api/cms_site_config_create.dspy",
|
||||
"/entcms/api/cms_site_config_update.dspy",
|
||||
"/entcms/api/cms_site_config_delete.dspy",
|
||||
"/entcms/api/cms_site_config_list.dspy",
|
||||
"/cms_site_config_list", "/cms_site_config_list/%",
|
||||
"/api/cms_site_config_create.dspy",
|
||||
"/api/cms_site_config_update.dspy",
|
||||
"/api/cms_site_config_delete.dspy",
|
||||
"/api/cms_site_config_list.dspy",
|
||||
# 线索管理
|
||||
"/entcms/cms_leads_list", "/entcms/cms_leads_list/%",
|
||||
"/entcms/api/cms_leads_create.dspy",
|
||||
"/entcms/api/cms_leads_update.dspy",
|
||||
"/entcms/api/cms_leads_delete.dspy",
|
||||
"/entcms/api/cms_leads_list.dspy",
|
||||
"/cms_leads_list", "/cms_leads_list/%",
|
||||
"/api/cms_leads_create.dspy",
|
||||
"/api/cms_leads_update.dspy",
|
||||
"/api/cms_leads_delete.dspy",
|
||||
"/api/cms_leads_list.dspy",
|
||||
# 审批
|
||||
"/entcms/api/submit_content_approval.dspy",
|
||||
"/api/submit_content_approval.dspy",
|
||||
]
|
||||
|
||||
# ─── reviewer — 查看内容 + 审批(只改status) ───
|
||||
reviewer_paths = [
|
||||
"/entcms",
|
||||
"/entcms/admin.ui",
|
||||
"/entcms/cms_content_list", "/entcms/cms_content_list/%",
|
||||
"/entcms/api/cms_content_list.dspy",
|
||||
"/entcms/api/cms_content_update.dspy", # 仅更新status字段
|
||||
"/entcms/api/category_options.dspy",
|
||||
"/admin.ui",
|
||||
"/cms_content_list", "/cms_content_list/%",
|
||||
"/api/cms_content_list.dspy",
|
||||
"/api/cms_content_update.dspy",
|
||||
"/api/category_options.dspy",
|
||||
]
|
||||
|
||||
# ─── supervisor — 查看全部 + 审批配置 + 线索管理 ───
|
||||
supervisor_paths = [
|
||||
"/entcms",
|
||||
"/entcms/admin.ui",
|
||||
# 只读
|
||||
"/entcms/cms_content_list", "/entcms/cms_content_list/%",
|
||||
"/entcms/cms_categories_list", "/entcms/cms_categories_list/%",
|
||||
"/entcms/cms_sections_list", "/entcms/cms_sections_list/%",
|
||||
"/entcms/cms_site_config_list", "/entcms/cms_site_config_list/%",
|
||||
# 列表API(只读)
|
||||
"/entcms/api/cms_content_list.dspy",
|
||||
"/entcms/api/cms_categories_list.dspy",
|
||||
"/entcms/api/cms_sections_list.dspy",
|
||||
"/entcms/api/cms_site_config_list.dspy",
|
||||
"/entcms/api/category_options.dspy",
|
||||
# 线索全权
|
||||
"/entcms/cms_leads_list", "/entcms/cms_leads_list/%",
|
||||
"/entcms/api/cms_leads_create.dspy",
|
||||
"/entcms/api/cms_leads_update.dspy",
|
||||
"/entcms/api/cms_leads_delete.dspy",
|
||||
"/entcms/api/cms_leads_list.dspy",
|
||||
# 审批
|
||||
"/entcms/api/submit_content_approval.dspy",
|
||||
"/admin.ui",
|
||||
"/cms_content_list", "/cms_content_list/%",
|
||||
"/cms_categories_list", "/cms_categories_list/%",
|
||||
"/cms_sections_list", "/cms_sections_list/%",
|
||||
"/cms_site_config_list", "/cms_site_config_list/%",
|
||||
"/api/cms_content_list.dspy",
|
||||
"/api/cms_categories_list.dspy",
|
||||
"/api/cms_sections_list.dspy",
|
||||
"/api/cms_site_config_list.dspy",
|
||||
"/api/category_options.dspy",
|
||||
"/cms_leads_list", "/cms_leads_list/%",
|
||||
"/api/cms_leads_create.dspy",
|
||||
"/api/cms_leads_update.dspy",
|
||||
"/api/cms_leads_delete.dspy",
|
||||
"/api/cms_leads_list.dspy",
|
||||
"/api/submit_content_approval.dspy",
|
||||
]
|
||||
|
||||
# ─── customer-support — 线索查看和更新 ───
|
||||
support_paths = [
|
||||
"/entcms",
|
||||
"/entcms/admin.ui",
|
||||
"/entcms/cms_leads_list", "/entcms/cms_leads_list/%",
|
||||
"/entcms/api/cms_leads_list.dspy",
|
||||
"/entcms/api/cms_leads_update.dspy",
|
||||
"/admin.ui",
|
||||
"/cms_leads_list", "/cms_leads_list/%",
|
||||
"/api/cms_leads_list.dspy",
|
||||
"/api/cms_leads_update.dspy",
|
||||
]
|
||||
|
||||
print("=== entcms RBAC权限配置 ===")
|
||||
print("=== CMS RBAC权限配置 ===")
|
||||
print(f"\n--- any (匿名用户) ---")
|
||||
run("any", any_paths)
|
||||
print(f"\n--- owner.webmaster (内容管理员) ---")
|
||||
|
||||
@ -47,7 +47,7 @@
|
||||
"actiontype": "urlwidget",
|
||||
"target": "app.sage_main_content",
|
||||
"options": {
|
||||
"url": "{{entire_url('/entcms/cms_content_list')}}"
|
||||
"url": "{{entire_url('/cms_content_list')}}"
|
||||
},
|
||||
"mode": "replace"
|
||||
}
|
||||
@ -102,7 +102,7 @@
|
||||
"actiontype": "urlwidget",
|
||||
"target": "app.sage_main_content",
|
||||
"options": {
|
||||
"url": "{{entire_url('/entcms/cms_sections_list')}}"
|
||||
"url": "{{entire_url('/cms_sections_list')}}"
|
||||
},
|
||||
"mode": "replace"
|
||||
}
|
||||
@ -157,7 +157,7 @@
|
||||
"actiontype": "urlwidget",
|
||||
"target": "app.sage_main_content",
|
||||
"options": {
|
||||
"url": "{{entire_url('/entcms/cms_categories_list')}}"
|
||||
"url": "{{entire_url('/cms_categories_list')}}"
|
||||
},
|
||||
"mode": "replace"
|
||||
}
|
||||
@ -212,7 +212,7 @@
|
||||
"actiontype": "urlwidget",
|
||||
"target": "app.sage_main_content",
|
||||
"options": {
|
||||
"url": "{{entire_url('/entcms/cms_leads_list')}}"
|
||||
"url": "{{entire_url('/cms_leads_list')}}"
|
||||
},
|
||||
"mode": "replace"
|
||||
}
|
||||
@ -267,7 +267,7 @@
|
||||
"actiontype": "urlwidget",
|
||||
"target": "app.sage_main_content",
|
||||
"options": {
|
||||
"url": "{{entire_url('/entcms/cms_site_config_list')}}"
|
||||
"url": "{{entire_url('/cms_site_config_list')}}"
|
||||
},
|
||||
"mode": "replace"
|
||||
}
|
||||
|
||||
@ -6,37 +6,37 @@
|
||||
{
|
||||
"name": "cms_content_list",
|
||||
"label": "内容管理",
|
||||
"url": "{{entire_url('/entcms/cms_content_list')}}",
|
||||
"url": "{{entire_url('/cms_content_list')}}",
|
||||
"target": "app.sage_main_content"
|
||||
},
|
||||
{
|
||||
"name": "cms_sections_list",
|
||||
"label": "栏目管理",
|
||||
"url": "{{entire_url('/entcms/cms_sections_list')}}",
|
||||
"url": "{{entire_url('/cms_sections_list')}}",
|
||||
"target": "app.sage_main_content"
|
||||
},
|
||||
{
|
||||
"name": "cms_categories_list",
|
||||
"label": "内容分类",
|
||||
"url": "{{entire_url('/entcms/cms_categories_list')}}",
|
||||
"url": "{{entire_url('/cms_categories_list')}}",
|
||||
"target": "app.sage_main_content"
|
||||
},
|
||||
{
|
||||
"name": "cms_leads_list",
|
||||
"label": "商机线索",
|
||||
"url": "{{entire_url('/entcms/cms_leads_list')}}",
|
||||
"url": "{{entire_url('/cms_leads_list')}}",
|
||||
"target": "app.sage_main_content"
|
||||
},
|
||||
{
|
||||
"name": "cms_site_config_list",
|
||||
"label": "站点配置",
|
||||
"url": "{{entire_url('/entcms/cms_site_config_list')}}",
|
||||
"url": "{{entire_url('/cms_site_config_list')}}",
|
||||
"target": "app.sage_main_content"
|
||||
},
|
||||
{
|
||||
"name": "public_site",
|
||||
"label": "官网预览",
|
||||
"url": "{{entire_url('/entcms/index.ui')}}",
|
||||
"url": "{{entire_url('/index.ui')}}",
|
||||
"target": "app.sage_main_content"
|
||||
}
|
||||
]
|
||||
|
||||
17
pyproject.toml
Normal file
17
pyproject.toml
Normal file
@ -0,0 +1,17 @@
|
||||
[build-system]
|
||||
requires = ["setuptools>=45", "wheel"]
|
||||
build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "kaiyuan-cms"
|
||||
version = "1.0.0"
|
||||
description = "开元云科技企业官网CMS系统 — 独立Web应用"
|
||||
requires-python = ">=3.8"
|
||||
dependencies = [
|
||||
"sqlor",
|
||||
"bricks_for_python",
|
||||
]
|
||||
|
||||
[tool.setuptools.packages.find]
|
||||
where = ["."]
|
||||
include = ["entcms*", "dingdingflow*"]
|
||||
@ -1,15 +1,41 @@
|
||||
"""
|
||||
初始化超级用户
|
||||
用法: cd ~/repos/sage && ./py3/bin/python ~/repos/cms/scripts/init_superuser.py [username] [password]
|
||||
用法:
|
||||
CMS环境: py3/bin/python scripts/init_superuser.py [username] [password]
|
||||
Sage环境: cd ~/repos/sage && ./py3/bin/python ~/repos/cms/scripts/init_superuser.py [username] [password]
|
||||
默认: admin / admin123
|
||||
"""
|
||||
import os, sys, asyncio
|
||||
|
||||
# 自动检测运行环境
|
||||
def find_workdir():
|
||||
"""查找应用根目录"""
|
||||
script_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
cms_root = os.path.dirname(script_dir)
|
||||
|
||||
# 检查是否是CMS独立环境
|
||||
if os.path.isdir(os.path.join(cms_root, "py3", "bin")) and \
|
||||
os.path.isfile(os.path.join(cms_root, "conf", "config.json")):
|
||||
return cms_root
|
||||
|
||||
# 检查Sage环境
|
||||
for c in [os.path.expanduser("~/repos/sage"), os.path.expanduser("~/sage")]:
|
||||
if os.path.isdir(os.path.join(c, "py3", "bin")):
|
||||
return c
|
||||
return None
|
||||
|
||||
workdir = find_workdir()
|
||||
if not workdir:
|
||||
print("ERROR: 找不到CMS或Sage应用目录")
|
||||
sys.exit(1)
|
||||
|
||||
# 确保Python路径
|
||||
sys.path.insert(0, os.path.join(workdir, "py3", "lib"))
|
||||
os.chdir(workdir)
|
||||
|
||||
from sqlor.dbpools import DBPools
|
||||
from appPublic.jsonConfig import getConfig
|
||||
from appPublic.uniqueID import getID
|
||||
|
||||
# Sage环境导入password_encode
|
||||
sys.path.insert(0, os.path.expanduser("~/repos/sage"))
|
||||
from appPublic.password import password_encode
|
||||
|
||||
async def main():
|
||||
@ -23,7 +49,6 @@ async def main():
|
||||
existing = await sor.R('users', {'username': username})
|
||||
if existing:
|
||||
print(f"用户 {username} 已存在 (id={existing[0]['id']})")
|
||||
# 更新密码
|
||||
await sor.U('users', {
|
||||
'id': existing[0]['id'],
|
||||
'passwd': password_encode(password)
|
||||
@ -59,8 +84,7 @@ async def main():
|
||||
users = await sor.R('users', {'username': username})
|
||||
uid = users[0]['id']
|
||||
|
||||
# 查找或创建用户-角色关联 (userrole表)
|
||||
# 检查userrole表是否存在
|
||||
# 分配角色
|
||||
try:
|
||||
ur = await sor.R('userrole', {'userid': uid, 'roleid': role_id})
|
||||
if not ur:
|
||||
@ -75,6 +99,24 @@ async def main():
|
||||
except Exception as e:
|
||||
print(f"注意: userrole表操作异常: {e}")
|
||||
print("可能需要手动分配角色")
|
||||
|
||||
# 给superuser分配全部权限
|
||||
try:
|
||||
all_perms = await sor.R('permission', {})
|
||||
for perm in all_perms:
|
||||
existing_rp = await sor.R('rolepermission', {
|
||||
'roleid': role_id,
|
||||
'permid': perm['id']
|
||||
})
|
||||
if not existing_rp:
|
||||
await sor.C('rolepermission', {
|
||||
'id': getID(),
|
||||
'roleid': role_id,
|
||||
'permid': perm['id']
|
||||
})
|
||||
print(f"已将全部 {len(all_perms)} 条权限分配给 owner.superuser")
|
||||
except Exception as e:
|
||||
print(f"注意: 权限分配异常: {e}")
|
||||
|
||||
print(f"\n登录信息:")
|
||||
print(f" 用户名: {username}")
|
||||
|
||||
11
start.sh
Executable file
11
start.sh
Executable file
@ -0,0 +1,11 @@
|
||||
#!/usr/bin/bash
|
||||
# CMS独立应用启动脚本
|
||||
cd "$(dirname "$0")"
|
||||
WORKDIR="$(pwd)"
|
||||
PIDFILE="$WORKDIR/cms.pid"
|
||||
|
||||
echo "启动 CMS Web Application (port 9090)..."
|
||||
$WORKDIR/py3/bin/python $WORKDIR/app/cms.py -p 9090 -w $WORKDIR &
|
||||
echo $! > $PIDFILE
|
||||
echo "CMS started (PID: $(cat $PIDFILE))"
|
||||
exit 0
|
||||
22
stop.sh
Executable file
22
stop.sh
Executable file
@ -0,0 +1,22 @@
|
||||
#!/usr/bin/bash
|
||||
# CMS独立应用停止脚本
|
||||
cd "$(dirname "$0")"
|
||||
PIDFILE="$(pwd)/cms.pid"
|
||||
|
||||
if [ -f "$PIDFILE" ]; then
|
||||
PID=$(cat "$PIDFILE")
|
||||
if kill -0 "$PID" 2>/dev/null; then
|
||||
echo "停止 CMS (PID: $PID)..."
|
||||
kill "$PID"
|
||||
sleep 2
|
||||
if kill -0 "$PID" 2>/dev/null; then
|
||||
kill -9 "$PID"
|
||||
fi
|
||||
echo "CMS已停止"
|
||||
else
|
||||
echo "CMS进程已不存在"
|
||||
fi
|
||||
rm -f "$PIDFILE"
|
||||
else
|
||||
echo "未找到PID文件"
|
||||
fi
|
||||
Loading…
x
Reference in New Issue
Block a user