diff --git a/rust-backend-dev.service b/rust-backend-dev.service deleted file mode 100644 index d9154a0..0000000 --- a/rust-backend-dev.service +++ /dev/null @@ -1,28 +0,0 @@ -[Unit] -Description=Rust Backend Development Service -After=network.target postgresql.service -Wants=network.target - -[Service] -Type=simple -User=root -Group=root -WorkingDirectory=/root/rust/rust_backend_dev -ExecStart=/root/rust/rust_backend_dev/rust-backend -Restart=always -RestartSec=5 -StandardOutput=journal -StandardError=journal - -EnvironmentFile=/root/rust/rust_backend_dev/.env - -NoNewPrivileges=yes -PrivateTmp=yes -ProtectSystem=strict -ProtectHome=read-only -ReadWritePaths=/root/rust/rust_backend_dev - -SyslogIdentifier=rust-backend-dev - -[Install] -WantedBy=multi-user.target diff --git a/rust-backend-dev.service b/rust-backend-dev.service new file mode 120000 index 0000000..a2ae1af --- /dev/null +++ b/rust-backend-dev.service @@ -0,0 +1 @@ +deploy/rust-backend-development.service \ No newline at end of file diff --git a/rust-backend.service b/rust-backend.service deleted file mode 100644 index a4479ce..0000000 --- a/rust-backend.service +++ /dev/null @@ -1,31 +0,0 @@ -[Unit] -Description=Rust Backend Service (Weather Data Collection API) -After=network.target postgresql.service -Wants=network.target - -[Service] -Type=simple -User=root -Group=root -WorkingDirectory=/root/rust/rust_backend -ExecStart=/root/rust/rust_backend/rust-backend -Restart=always -RestartSec=5 -StandardOutput=journal -StandardError=journal - -# 环境变量配置 -EnvironmentFile=/root/rust/rust_backend/.env - -# 安全加固 -NoNewPrivileges=yes -PrivateTmp=yes -ProtectSystem=strict -ProtectHome=read-only -ReadWritePaths=/root/rust/rust_backend - -# 日志标识 -SyslogIdentifier=rust-backend - -[Install] -WantedBy=multi-user.target \ No newline at end of file diff --git a/rust-backend.service b/rust-backend.service new file mode 120000 index 0000000..1a1b5e9 --- /dev/null +++ b/rust-backend.service @@ -0,0 +1 @@ +deploy/rust-backend-prod.service \ No newline at end of file diff --git a/scripts/expire-paid-user.sh b/scripts/expire-paid-user.sh index 3ba816f..7707340 100755 --- a/scripts/expire-paid-user.sh +++ b/scripts/expire-paid-user.sh @@ -1,19 +1,11 @@ #!/bin/bash -# scripts/expire-paid-user.sh -# 通过 SSH 在服务器上执行 SQL,使用户的付费时间过期(仅修改 paid_expires_at) -# 与 set-paid-user.sh --expires 的区别:此脚本专用于"过期"场景, -# 保持 is_paid=true(用户仍标记为付费),仅将 paid_expires_at 设到过去。 -# -# 使用 config/development.toml 中的数据库配置 -# 密码由服务器的 1panel/环境变量提供,无需手动传入 -# -# 用法: -# ./scripts/expire-paid-user.sh -# ./scripts/expire-paid-user.sh --date YYYY-MM-DD -# -# 示例: -# ./scripts/expire-paid-user.sh 1 # 设为昨天到期(立即过期) -# ./scripts/expire-paid-user.sh 1 --date 2025-01-01 # 设为指定日期到期(已过期) +# =========================================== +# 通过 SSH 在服务器上执行 SQL,使用户的付费时间过期 +# 仅修改 membership_expires_at 到过去日期 +# is_member 保持 true,is_active_member 会变为 false +# =========================================== + +set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" PROJECT_ROOT="$(dirname "$SCRIPT_DIR")" @@ -28,187 +20,68 @@ usage() { echo "用法: $0 [--date YYYY-MM-DD]" echo "" echo " user_id 用户 ID(必填)" - echo " --date DATE 指定过期日期(默认: 昨天)" - echo "" - echo "说明:" - echo " 将用户 paid_expires_at 设到过去日期(is_paid 保持 true)" - echo " 用户的 is_paid_active 会变为 false" - echo "" - echo "数据源:" - echo " SSH 服务器: .env 中 SSH_SERVER" - echo " 数据库配置: config/development.toml (host/port/dbname)" - echo " 密码: 服务器上的环境变量/1panel 自动提供" + echo " --date YYYY-MM-DD 指定到期日期(默认:昨天,即立即过期)" echo "" echo "示例:" - echo " $0 1 # 设为昨天到期" - echo " $0 1 --date 2025-01-01 # 设为 2025-01-01" + echo " $0 1 # 用户 1 立即过期" + echo " $0 1 --date 2025-01-01 # 用户 1 在 2025-01-01 过期" exit 0 } -validate_date() { - local date="$1" - if [[ ! "$date" =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2}$ ]]; then - echo "错误: 日期格式无效,请使用 YYYY-MM-DD" - exit 1 - fi -} +# ---------- 参数解析 ---------- +USER_ID="" +EXPIRES_DATE="" -# 解析 toml 文件中的 database_url -parse_toml_db_url() { - local file="$1" - grep '^database_url' "$file" 2>/dev/null | head -1 | sed 's/^database_url *= *["'"'"']//' | sed 's/["'"'"']*$//' | tr -d ' ' -} +while [[ $# -gt 0 ]]; do + case "$1" in + --date) EXPIRES_DATE="$2"; shift 2 ;; + --help|-h) usage ;; + *) USER_ID="$1"; shift ;; + esac +done -# 解析 postgres:// URL -parse_db_url() { - local db_url="$1" - local rest="${db_url#postgres://}" - DB_USER="${rest%%:*}" - local host_port="${rest##*@}" - host_port="${host_port%%/*}" - if [[ "$host_port" == *:* ]]; then - DB_HOST="${host_port%%:*}" - DB_PORT="${host_port##*:}" - else - DB_HOST="$host_port" - DB_PORT="5432" - fi - DB_NAME="${rest##*/}" - DB_NAME="${DB_NAME%%\?*}" -} +[ -z "$USER_ID" ] && usage -info() { echo "[INFO] $1"; } -warn() { echo "[WARN] $1"; } -error() { echo "[ERROR] $1" >&2; } -step() { echo ""; echo ">>> 第 $1 步: $2"; echo ""; } +# ---------- 连接信息 ---------- +SSH_HOST=$(get_ssh_host) +[ -z "$SSH_HOST" ] && { echo "错误: 未配置 SSH_SERVER"; exit 1; } -# 在服务器上通过 docker exec 执行 SQL -exec_sql() { - local sql="$1" - ssh -o BatchMode=yes -o StrictHostKeyChecking=no -o ConnectTimeout=5 "$SSH_HOST" \ - "cd /root/rust/rust_backend_dev 2>/dev/null || true; docker exec 1Panel-postgresql-FtMo psql -U ${DB_USER} -d ${DB_NAME} -c \"${sql}\"" 2>&1 -} +DB_CONTAINER="1Panel-postgresql-FtMo" +DB_NAME="milkydata" +DB_USER="milkydata" -main() { - if [[ $# -lt 1 ]]; then - usage - fi +# ---------- 设置过期日期 ---------- +if [ -z "$EXPIRES_DATE" ]; then + EXPIRES_DATE=$(date -d "yesterday" +%Y-%m-%d) + echo "未指定日期,默认设为昨天: ${EXPIRES_DATE}" +fi - USER_ID="$1" - shift +echo "═══════════════════════════════════════" +echo "用户 ${USER_ID} 会员过期操作" +echo "到期日期: ${EXPIRES_DATE}" +echo "═══════════════════════════════════════" - if [[ ! "$USER_ID" =~ ^[0-9]+$ ]]; then - error "user_id 必须是数字" - exit 1 - fi +echo "" - EXPIRES_DATE="" +echo "⚠️ 即将执行以下操作:" +echo " 将用户 ${USER_ID} 的 membership_expires_at 设到 ${EXPIRES_DATE}" +echo " is_member 保持 true(用户仍标记为曾付费)" +echo " 用户的 is_active_member 会变为 false(付费已过期)" +echo "" +read -p "确认执行? [y/N] " -n 1 -r; echo +[[ ! $REPLY =~ ^[Yy]$ ]] && { echo "已取消"; exit 0; } - while [[ $# -gt 0 ]]; do - case "$1" in - --date) - EXPIRES_DATE="$2" - validate_date "$EXPIRES_DATE" - shift 2 - ;; - -h|--help) usage ;; - *) error "未知参数: $1"; usage ;; - esac - done +# ---------- 执行 SQL ---------- +SQL="UPDATE users SET is_member = true, membership_expires_at = '${EXPIRES_DATE}'::date WHERE id = ${USER_ID};" - # 默认过期日期:昨天 - if [[ -z "$EXPIRES_DATE" ]]; then - if date --version 2>/dev/null | grep -q GNU; then - EXPIRES_DATE=$(date -d "yesterday" "+%Y-%m-%d") - else - EXPIRES_DATE=$(date -v -1d "+%Y-%m-%d") - fi - fi +echo "执行 SQL: ${SQL}" +ssh "$SSH_HOST" "docker exec ${DB_CONTAINER} psql -U ${DB_USER} -d ${DB_NAME} -c \"${SQL}\"" && echo "✅ 操作成功" || echo "❌ 操作失败" - # ===== Step 1: 读取配置 ===== - step 1 "读取配置" +# 查询验证 +QUERY_SQL="SELECT id, name, phone, type, is_member, is_admin, membership_expires_at FROM users WHERE id = ${USER_ID};" +echo "" +echo "验证结果:" +ssh "$SSH_HOST" "docker exec ${DB_CONTAINER} psql -U ${DB_USER} -d ${DB_NAME} -c \"${QUERY_SQL}\"" - SSH_HOST="$(get_ssh_host)" - if [[ -z "$SSH_HOST" ]]; then - error "未找到 SSH_SERVER 配置,请检查 .env 文件" - exit 1 - fi - info "SSH 服务器: $SSH_HOST" - - CONFIG_FILE="$CONFIG_DIR/development.toml" - if [[ ! -f "$CONFIG_FILE" ]]; then - error "配置文件不存在: $CONFIG_FILE" - exit 1 - fi - - TOML_DB_URL="$(parse_toml_db_url "$CONFIG_FILE")" - if [[ -z "$TOML_DB_URL" ]]; then - error "development.toml 中未找到 database_url" - exit 1 - fi - - parse_db_url "$TOML_DB_URL" - info "数据库: ${DB_USER}@${DB_HOST}:${DB_PORT}/${DB_NAME}" - - # ===== Step 2: 构造 SQL ===== - step 2 "构造 SQL 语句" - - SQL="UPDATE users SET is_paid = true, paid_expires_at = '${EXPIRES_DATE}'::date WHERE id = ${USER_ID};" - info "设置过期日期: $EXPIRES_DATE" - echo " SQL: $SQL" - - # ===== Step 3: 执行 SQL ===== - step 3 "通过 SSH 在服务器上执行 SQL" - - info "连接 $SSH_HOST (超时 15s) ..." - - SQL_RAW=$(exec_sql "$SQL") - SQL_EXIT=$? - - if [[ $SQL_EXIT -ne 0 ]]; then - error "执行失败(退出码: $SQL_EXIT)" - echo "$SQL_RAW" | sed 's/^/ /' >&2 - exit 1 - fi - - echo "$SQL_RAW" - if echo "$SQL_RAW" | grep -q "UPDATE [01]"; then - ROWS=$(echo "$SQL_RAW" | grep "UPDATE" | grep -oP '\d+' | head -1) - if [[ "${ROWS:-0}" == "0" ]]; then - warn "未更新任何行(用户 ID $USER_ID 可能不存在)" - else - info "成功更新 ${ROWS} 行" - fi - else - warn "无法确认更新结果" - fi - - # ===== Step 4: 验证结果 ===== - step 4 "查询用户信息确认" - - QUERY_SQL="SELECT id, name, phone, type, is_paid, is_admin, paid_expires_at FROM users WHERE id = ${USER_ID};" - info "SQL: $QUERY_SQL" - QUERY_RAW=$(exec_sql "$QUERY_SQL") - QUERY_EXIT=$? - - if [[ $QUERY_EXIT -ne 0 ]]; then - warn "查询失败(退出码: $QUERY_EXIT),但数据更新已执行" - echo "$QUERY_RAW" | sed 's/^/ /' - else - echo "$QUERY_RAW" - fi - - # ===== 总结 ===== - echo "" - echo "============================================" - echo " 执行完成" - echo "============================================" - echo " 用户 ID: $USER_ID" - echo " 过期日期: $EXPIRES_DATE" - echo " 服务器: $SSH_HOST" - echo "============================================" - echo "" - echo "提示: is_paid 保持 true,is_paid_active 会变为 false(付费已过期)" -} - -main "$@" +echo "" +echo "提示: is_member 保持 true,is_active_member 会变为 false(付费已过期)"