#!/usr/bin/env bash # set-license-expiry.sh <门店编号> <带符号天数> # # 测试工具:把某门店「当前有效授权」(licenses.is_active=1) 的到期时间改成 # 「相对现在 N 天」,方便快速切换授权阶段验证客户端表现。 # # 带符号天数 DAYS: # 30 -> 30 天后到期 → normal 正常(未过期) # 0 -> 今天到期 # -6 -> 已过期 6 天 → grace 宽限期(仍可登录,有横幅) # -10 -> 已过期 10 天 → readonly 只读(可登录,禁写) # -20 -> 已过期 20 天 → locked 锁定(无法登录) # # 默认改「线上 prod」EC2 上 jiu_mysql 容器里的 jiu_db.licenses。 # 连接参数可用环境变量覆盖: # EC2_HOST (默认 18.136.60.128) # EC2_USER (默认 ec2-user) # SSH_KEY (默认 ~/.ssh/wangjia.pem) # # 用法示例: # sh scripts/set-license-expiry.sh S003 -6 # S003 → 已过期 6 天(grace) # sh scripts/set-license-expiry.sh S003 30 # S003 → 恢复,30 天后到期 set -euo pipefail SHOP="${1:-}" DAYS="${2:-}" if [ -z "$SHOP" ] || [ -z "$DAYS" ]; then echo "用法: $0 <门店编号> <带符号天数>" >&2 echo "示例: $0 S003 -6 # S003 授权改为已过期 6 天(grace 宽限期)" >&2 echo " $0 S003 30 # S003 授权恢复,30 天后到期" >&2 exit 1 fi case "$DAYS" in ''|*[!0-9-]*) echo "错误: 天数必须是整数(可带负号),收到: '$DAYS'" >&2; exit 1;; esac EC2_HOST="${EC2_HOST:-18.136.60.128}" EC2_USER="${EC2_USER:-ec2-user}" SSH_KEY="${SSH_KEY:-$HOME/.ssh/wangjia.pem}" echo "==> 目标(线上 prod): ${EC2_USER}@${EC2_HOST} 门店=${SHOP} 到期=现在 ${DAYS} 天" # 全部在远端单次 ssh 内完成;DB 密码只在远端从 production.env 读取,绝不打印/外传。 ssh -o ConnectTimeout=10 -o StrictHostKeyChecking=accept-new -i "$SSH_KEY" \ "${EC2_USER}@${EC2_HOST}" bash -s -- "$SHOP" "$DAYS" <<'ENDSSH' set -euo pipefail SHOP="$1"; DAYS="$2" sudo grep '^DB_PASSWORD=' /opt/jiu/config/production.env | cut -d= -f2- | { read -r PW MYSQL() { sudo docker exec -i jiu_mysql mysql --default-character-set=utf8mb4 -uroot -p"$PW" jiu_db "$@"; } echo "--- 改前 ---" MYSQL -e "SELECT s.code, s.name, l.id, l.type, l.is_active, l.expires_at, TIMESTAMPDIFF(DAY, l.expires_at, NOW()) AS days_expired FROM licenses l JOIN shops s ON s.id = l.shop_id WHERE s.code = '${SHOP}' AND l.is_active = 1 ORDER BY l.id DESC;" MYSQL -e "UPDATE licenses SET expires_at = DATE_ADD(NOW(), INTERVAL ${DAYS} DAY) WHERE shop_id = (SELECT id FROM shops WHERE code = '${SHOP}' LIMIT 1) AND is_active = 1;" echo "--- 改后 ---" MYSQL -e "SELECT s.code, l.id, l.expires_at, TIMESTAMPDIFF(DAY, l.expires_at, NOW()) AS days_expired FROM licenses l JOIN shops s ON s.id = l.shop_id WHERE s.code = '${SHOP}' AND l.is_active = 1 ORDER BY l.id DESC;" } ENDSSH # 阶段提示(与后端 middleware.CalcLicensePhase 边界一致:grace<=7天, readonly<=15天, locked>15天) if [ "$DAYS" -ge 0 ]; then PHASE="normal 正常(未过期)" else EXP=$(( -DAYS )) if [ "$EXP" -le 7 ]; then PHASE="grace 宽限期(仍可登录,有横幅提醒)" elif [ "$EXP" -le 15 ]; then PHASE="readonly 只读(可登录,所有写操作被禁)" else PHASE="locked 锁定(无法登录,登录页给出续费入口)" fi fi echo "==> 完成。预计阶段: ${PHASE}" echo "==> 提示: 后端 phase 有约 30s 的每店缓存;已登录的客户端会话需等 ~30s 或重新登录后生效。"