#!/bin/bash # =========================================== # 发送通知 - 管理员工具 # 通过 API 创建系统广播或定向通知 # =========================================== # 用法: # ./scripts/send-notification.sh --all --type system_maintenance --title "维护通知" --content "内容" # ./scripts/send-notification.sh --user 1 --type payment_success --title "开通成功" --link /upgrade # # 选项: # --all 发送给所有用户(scope=all) # --user 发送给指定用户(scope=user) # --type 通知类型(必填) # --title 通知标题(必填) # --content 通知内容(可选) # --priority 优先级: high/normal/low(默认 normal) # --link 点击跳转路径(可选) # --dev 目标: milkydata_dev(默认 milkydata) # --dry-run 预览不执行 # =========================================== set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" PROJECT_ROOT="$(dirname "$SCRIPT_DIR")" ENV_FILE="$PROJECT_ROOT/.env" # ---------- 默认值 ---------- SCOPE="" USER_ID="" NOTIF_TYPE="" TITLE="" CONTENT="" PRIORITY="normal" LINK="" DB_NAME="milkydata" DRY_RUN=false # ---------- 获取 SSH 主机 ---------- get_ssh_host() { grep '^SSH_SERVER=' "$ENV_FILE" 2>/dev/null | head -1 | cut -d'=' -f2- | tr -d '"' | tr -d "'" | xargs } # ---------- 使用说明 ---------- usage() { echo "用法: $0 (--all | --user ) --type --title [options]" echo "" echo "必填:" echo " --all 发送给所有用户" echo " --user <id> 发送给指定用户" echo " --type <type> 通知类型: system_maintenance / version_update /" echo " payment_success / member_expiry_soon / member_expired" echo " --title <text> 通知标题" echo "" echo "可选:" echo " --content <text> 通知内容" echo " --priority <lvl> high / normal / low(默认 normal)" echo " --link <path> 点击跳转路径(如 /pkg-extra/upgrade/upgrade)" echo " --dev 操作开发库 milkydata_dev" echo " --dry-run 预览,不执行" echo "" echo "示例:" echo " $0 --all --type system_maintenance --title '维护通知' --content '今晚维护' --priority high" echo " $0 --user 1 --type payment_success --title '开通成功' --link /upgrade --dev" exit 0 } # ---------- 参数解析 ---------- while [[ $# -gt 0 ]]; do case "$1" in --all) SCOPE="all" ;; --user) SCOPE="user"; USER_ID="$2"; shift ;; --type) NOTIF_TYPE="$2"; shift ;; --title) TITLE="$2"; shift ;; --content) CONTENT="$2"; shift ;; --priority) PRIORITY="$2"; shift ;; --link) LINK="$2"; shift ;; --dev) DB_NAME="milkydata_dev" ;; --dry-run) DRY_RUN=true ;; --help|-h) usage ;; *) echo "未知选项: $1"; usage ;; esac shift done # ---------- 必填校验 ---------- [ -z "$SCOPE" ] && { echo "错误: 必须指定 --all 或 --user"; usage; } [ "$SCOPE" = "user" ] && [ -z "$USER_ID" ] && { echo "错误: --user 必须指定用户 ID"; usage; } [ -z "$NOTIF_TYPE" ] && { echo "错误: --type 必填"; usage; } [ -z "$TITLE" ] && { echo "错误: --title 必填"; usage; } # ---------- 连接信息 ---------- SSH_HOST=$(get_ssh_host) [ -z "$SSH_HOST" ] && { echo "错误: 未配置 SSH_SERVER"; exit 1; } DB_CONTAINER="1Panel-postgresql-FtMo" DB_USER="milkydata" # ---------- 构建 SQL ---------- USER_VAL="NULL" [ "$SCOPE" = "user" ] && USER_VAL="$USER_ID" CONTENT_VAL="NULL" [ -n "$CONTENT" ] && CONTENT_VAL="'${CONTENT//\'/\'\'}'" LINK_VAL="NULL" [ -n "$LINK" ] && LINK_VAL="'${LINK//\'/\'\'}'" SQL="INSERT INTO notifications (scope, user_id, type, title, content, priority, link) VALUES ('${SCOPE}', ${USER_VAL}, '${NOTIF_TYPE}', '${TITLE//\'/\'\'}', ${CONTENT_VAL}, '${PRIORITY}', ${LINK_VAL});" # ---------- 确认信息 ---------- echo "" echo "═══════════════════════════════════════" echo " 操作: 发送通知" echo " 范围: ${SCOPE}" echo " 类型: ${NOTIF_TYPE}" echo " 标题: ${TITLE}" echo " 数据库: ${DB_NAME}(${SSH_HOST})" echo "═══════════════════════════════════════" echo "" echo "将要执行:" echo " ${SQL}" echo "" [ "$DRY_RUN" = true ] && { echo "预览模式,未执行。"; exit 0; } read -p "确认发送? [y/N] " -n 1 -r; echo [[ ! $REPLY =~ ^[Yy]$ ]] && { echo "已取消"; exit 0; } echo "" echo "执行中..." ssh "$SSH_HOST" "docker exec ${DB_CONTAINER} psql -U ${DB_USER} -d ${DB_NAME} -c \"${SQL}\"" && echo "✅ 通知已发送" || echo "❌ 发送失败" # 验证 echo "" echo "最近通知:" VERIFY_SQL="SELECT id, scope, user_id, type, title, priority, created_at::date FROM notifications ORDER BY id DESC LIMIT 5;" ssh "$SSH_HOST" "docker exec ${DB_CONTAINER} psql -U ${DB_USER} -d ${DB_NAME} -c \"${VERIFY_SQL}\"" echo ""