From fc6f19347968f2d46eb7a9bef262768d4f980367 Mon Sep 17 00:00:00 2001 From: shanshanzhong Date: Tue, 2 Jun 2026 20:56:05 -0700 Subject: [PATCH] Clean repository development artifacts --- .codex-tmp/inspect_device_cache_roundtrip.go | 25 - .codex-tmp/inspect_device_config.go | 23 - .codex-tmp/inspect_device_db_vs_model.go | 36 - .codex-tmp/inspect_device_gorm.go | 28 - .gitea/workflows/docker.yml | 337 --------- .github/environments/production.yml | 27 - .github/environments/staging.yml | 23 - .github/workflows/deploy-linux.yml | 79 -- .gitignore | 8 + .goreleaser.yaml | 66 -- deliverables/ec2-ssh/README.txt | 20 - deliverables/ec2-ssh/hifast-hk-app-01-reset | 8 - .../ec2-ssh/hifast-hk-app-01-reset.pub | 1 - .../configs/resource-inventory.current.md | 3 +- .../ap-northeast-1/keys/ppanel-jp-recovery | 7 - .../keys/ppanel-jp-recovery.pub | 1 - docker-compose.yml | 2 - queue/logic/order/activateOrderLogic.go_bak | 675 ------------------ 迁移到命令.txt | 44 -- 19 files changed, 9 insertions(+), 1404 deletions(-) delete mode 100644 .codex-tmp/inspect_device_cache_roundtrip.go delete mode 100644 .codex-tmp/inspect_device_config.go delete mode 100644 .codex-tmp/inspect_device_db_vs_model.go delete mode 100644 .codex-tmp/inspect_device_gorm.go delete mode 100644 .gitea/workflows/docker.yml delete mode 100644 .github/environments/production.yml delete mode 100644 .github/environments/staging.yml delete mode 100644 .github/workflows/deploy-linux.yml delete mode 100644 .goreleaser.yaml delete mode 100644 deliverables/ec2-ssh/README.txt delete mode 100644 deliverables/ec2-ssh/hifast-hk-app-01-reset delete mode 100644 deliverables/ec2-ssh/hifast-hk-app-01-reset.pub delete mode 100644 deploy/aws/ap-northeast-1/keys/ppanel-jp-recovery delete mode 100644 deploy/aws/ap-northeast-1/keys/ppanel-jp-recovery.pub delete mode 100644 queue/logic/order/activateOrderLogic.go_bak delete mode 100644 迁移到命令.txt diff --git a/.codex-tmp/inspect_device_cache_roundtrip.go b/.codex-tmp/inspect_device_cache_roundtrip.go deleted file mode 100644 index 4a6f5c6..0000000 --- a/.codex-tmp/inspect_device_cache_roundtrip.go +++ /dev/null @@ -1,25 +0,0 @@ -package main - -import ( - "fmt" - - "github.com/perfect-panel/server/internal/config" - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/pkg/conf" -) - -func main() { - var c config.Config - conf.MustLoad("/private/tmp/ppanel-local-upload.yaml", &c) - ctx := svc.NewServiceContext(c) - const key = "cache:auth:method:device" - before, _ := ctx.Redis.Get(ctx.DB.Statement.Context, key).Result() - fmt.Printf("cache before=%q\n", before) - m, err := ctx.AuthModel.FindOneByMethod(ctx.DB.Statement.Context, "device") - fmt.Printf("model err=%v enabled_nil=%v", err, m == nil || m.Enabled == nil) - if m != nil && m.Enabled != nil { fmt.Printf(" enabled=%v", *m.Enabled) } - if m != nil { fmt.Printf(" config=%s", m.Config) } - fmt.Println() - after, _ := ctx.Redis.Get(ctx.DB.Statement.Context, key).Result() - fmt.Printf("cache after=%q\n", after) -} diff --git a/.codex-tmp/inspect_device_config.go b/.codex-tmp/inspect_device_config.go deleted file mode 100644 index 9299623..0000000 --- a/.codex-tmp/inspect_device_config.go +++ /dev/null @@ -1,23 +0,0 @@ -package main - -import ( - "fmt" - - initpkg "github.com/perfect-panel/server/initialize" - "github.com/perfect-panel/server/internal/config" - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/pkg/conf" -) - -func main() { - var c config.Config - conf.MustLoad("/private/tmp/ppanel-local-upload.yaml", &c) - ctx := svc.NewServiceContext(c) - method, err := ctx.AuthModel.FindOneByMethod(ctx.DB.Statement.Context, "device") - if err != nil { - panic(err) - } - fmt.Printf("db auth_method.enabled=%v config=%s\n", *method.Enabled, method.Config) - initpkg.Device(ctx) - fmt.Printf("ctx.Config.Device.Enable=%v SecuritySecret=%q EnableSecurity=%v\n", ctx.Config.Device.Enable, ctx.Config.Device.SecuritySecret, ctx.Config.Device.EnableSecurity) -} diff --git a/.codex-tmp/inspect_device_db_vs_model.go b/.codex-tmp/inspect_device_db_vs_model.go deleted file mode 100644 index ee58a04..0000000 --- a/.codex-tmp/inspect_device_db_vs_model.go +++ /dev/null @@ -1,36 +0,0 @@ -package main - -import ( - "fmt" - - "github.com/perfect-panel/server/internal/config" - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/pkg/conf" -) - -type row struct { - ID int64 - Method string - Enabled int - Config string -} - -func main() { - var c config.Config - conf.MustLoad("/private/tmp/ppanel-local-upload.yaml", &c) - ctx := svc.NewServiceContext(c) - - var rows []row - if err := ctx.DB.Raw("SELECT id, method, enabled, config FROM auth_method WHERE method = ?", "device").Scan(&rows).Error; err != nil { - panic(err) - } - fmt.Printf("raw rows: %+v\n", rows) - - m, err := ctx.AuthModel.FindOneByMethod(ctx.DB.Statement.Context, "device") - fmt.Printf("model err=%v\n", err) - if err == nil && m != nil && m.Enabled != nil { - fmt.Printf("model row: id=%d method=%s enabled=%v config=%s\n", m.Id, m.Method, *m.Enabled, m.Config) - } else { - fmt.Printf("model row nil or no enabled ptr: %#v\n", m) - } -} diff --git a/.codex-tmp/inspect_device_gorm.go b/.codex-tmp/inspect_device_gorm.go deleted file mode 100644 index 7da8d6f..0000000 --- a/.codex-tmp/inspect_device_gorm.go +++ /dev/null @@ -1,28 +0,0 @@ -package main - -import ( - "fmt" - - "github.com/perfect-panel/server/internal/config" - authmodel "github.com/perfect-panel/server/internal/model/auth" - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/pkg/conf" -) - -func main() { - var c config.Config - conf.MustLoad("/private/tmp/ppanel-local-upload.yaml", &c) - ctx := svc.NewServiceContext(c) - - var a1 authmodel.Auth - err1 := ctx.DB.Model(&authmodel.Auth{}).Where("method = ?", "device").First(&a1).Error - fmt.Printf("gorm direct err=%v enabled_nil=%v", err1, a1.Enabled == nil) - if a1.Enabled != nil { fmt.Printf(" enabled=%v", *a1.Enabled) } - fmt.Printf(" config=%s\n", a1.Config) - - var a2 authmodel.Auth - err2 := ctx.DB.Table("auth_method").Where("method = ?", "device").First(&a2).Error - fmt.Printf("gorm table err=%v enabled_nil=%v", err2, a2.Enabled == nil) - if a2.Enabled != nil { fmt.Printf(" enabled=%v", *a2.Enabled) } - fmt.Printf(" config=%s\n", a2.Config) -} diff --git a/.gitea/workflows/docker.yml b/.gitea/workflows/docker.yml deleted file mode 100644 index 6057447..0000000 --- a/.gitea/workflows/docker.yml +++ /dev/null @@ -1,337 +0,0 @@ -name: Build docker and publish -run-name: 简化的Docker构建和部署流程 - -on: - push: - branches: - - main - - internal - pull_request: - branches: - - main - - internal - -env: - # Docker镜像仓库 - REPO: ${{ vars.REPO || 'registry.kxsw.us/vpn-server' }} - # SSH连接信息 (根据分支自动选择服务器和用户) - SSH_HOST: ${{ github.ref_name == 'main' && vars.SSH_HOST || vars.DEV_SSH_HOST }} - SSH_PORT: ${{ vars.SSH_PORT }} - SSH_USER: ${{ github.ref_name == 'main' && 'ubuntu' || 'root' }} - # SSH私钥(Gitea Secret 名称:AWS) - SSH_KEY: ${{ secrets.AWS }} - # TG通知 - TG_BOT_TOKEN: ${{ secrets.TG_BOT_TOKEN }} - TG_CHAT_ID: ${{ secrets.TG_CHAT_ID }} - # Go构建变量 - SERVICE: vpn - SERVICE_STYLE: vpn - VERSION: ${{ github.sha }} - BUILDTIME: ${{ github.event.head_commit.timestamp }} - GOARCH: amd64 - -jobs: - build: - runs-on: ario-server - container: - image: node:20 - strategy: - matrix: - # 只有node支持版本号别名 - node: ['20.15.1'] - steps: - # 步骤1: 下载代码 - - name: 📥 下载代码 - uses: actions/checkout@v4 - - # 步骤2: 设置动态环境变量 - - name: ⚙️ 设置动态环境变量 - run: | - if [ "${{ github.ref_name }}" = "main" ]; then - echo "DOCKER_TAG_SUFFIX=latest" >> $GITHUB_ENV - echo "CONTAINER_NAME=ppanel-server" >> $GITHUB_ENV - echo "DEPLOY_PATH=/opt/ppanel" >> $GITHUB_ENV - echo "DEPLOY_ENV_LABEL=🚀 服务已成功部署到生产环境" >> $GITHUB_ENV - echo "为 main 分支设置生产环境变量" - elif [ "${{ github.ref_name }}" = "internal" ]; then - echo "DOCKER_TAG_SUFFIX=internal" >> $GITHUB_ENV - echo "CONTAINER_NAME=ppanel-server-internal" >> $GITHUB_ENV - echo "DEPLOY_PATH=/root/bindbox" >> $GITHUB_ENV - echo "DEPLOY_ENV_LABEL=🧪 服务已成功部署到测试环境" >> $GITHUB_ENV - echo "为 internal 分支设置开发环境变量" - else - echo "DOCKER_TAG_SUFFIX=${{ github.ref_name }}" >> $GITHUB_ENV - echo "CONTAINER_NAME=ppanel-server-${{ github.ref_name }}" >> $GITHUB_ENV - echo "DEPLOY_PATH=/root/vpn_server_other" >> $GITHUB_ENV - echo "DEPLOY_ENV_LABEL=🔧 服务已成功部署到其他环境" >> $GITHUB_ENV - echo "为其他分支 (${{ github.ref_name }}) 设置环境变量" - fi - - # 步骤3: 安装系统工具 (curl, jq) 并升级 Docker CLI 到 1.44+ - - name: 🔧 安装系统工具并升级 Docker CLI - run: | - set -e - export DEBIAN_FRONTEND=noninteractive - echo "等待 apt/dpkg 锁释放 (unattended-upgrades)..." - end=$((SECONDS+300)) - while true; do - LOCKS_BUSY=0 - if pgrep -x unattended-upgrades >/dev/null 2>&1; then LOCKS_BUSY=1; fi - if command -v fuser >/dev/null 2>&1; then - if fuser /var/lib/dpkg/lock >/dev/null 2>&1 \ - || fuser /var/lib/dpkg/lock-frontend >/dev/null 2>&1 \ - || fuser /var/lib/apt/lists/lock >/dev/null 2>&1; then - LOCKS_BUSY=1 - fi - fi - if [ "$LOCKS_BUSY" -eq 0 ]; then break; fi - if [ $SECONDS -ge $end ]; then - echo "等待 apt/dpkg 锁超时,使用 Dpkg::Lock::Timeout 继续..." - break - fi - echo "仍在等待锁释放..."; sleep 5 - done - - # 基础工具 - apt-get update -y -o Dpkg::Lock::Timeout=600 - apt-get install -y -o Dpkg::Lock::Timeout=600 jq curl ca-certificates gnupg lsb-release - - # 移除旧版 docker.io,避免客户端过旧 (API 1.41) - if dpkg -s docker.io >/dev/null 2>&1; then - apt-get remove -y docker.io || true - fi - - # 安装 Docker 官方仓库的 CLI (确保 API >= 1.44) - distro_codename=$(. /etc/os-release && echo "$VERSION_CODENAME") - install_repo="deb [arch=amd64 signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian ${distro_codename} stable" - mkdir -p /etc/apt/keyrings - curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg - echo "$install_repo" > /etc/apt/sources.list.d/docker.list - apt-get update -y -o Dpkg::Lock::Timeout=600 - apt-get install -y -o Dpkg::Lock::Timeout=600 docker-ce-cli docker-buildx-plugin - - # 版本检查 - docker --version || true - docker version || true - echo "客户端 API 版本:" $(docker version --format '{{.Client.APIVersion}}') - - # 步骤4: 构建镜像 - - name: 🏗️ 构建镜像 - run: | - echo "开始构建镜像..." - echo "仓库: ${{ env.REPO }}" - echo "版本标签: ${{ env.VERSION }}" - echo "分支标签: ${{ env.DOCKER_TAG_SUFFIX }}" - - BUILD_TAG_ARGS="-t ${{ env.REPO }}:${{ env.VERSION }}" - if [ "${{ github.event_name }}" = "push" ]; then - BUILD_TAG_ARGS="$BUILD_TAG_ARGS -t ${{ env.REPO }}:${{ env.DOCKER_TAG_SUFFIX }}" - else - echo "PR事件仅构建版本标签,不推送镜像、不部署" - fi - - docker build -f Dockerfile \ - --platform linux/amd64 \ - --build-arg TARGETARCH=amd64 \ - --build-arg VERSION=${{ env.VERSION }} \ - --build-arg BUILDTIME=${{ env.BUILDTIME }} \ - $BUILD_TAG_ARGS \ - . - - echo "镜像构建完成" - - # 步骤5: 发布到镜像仓库 - - name: 📤 发布到镜像仓库 - if: github.event_name == 'push' - run: | - echo "开始推送镜像..." - - echo "推送版本标签镜像: ${{ env.REPO }}:${{ env.VERSION }}" - docker push ${{ env.REPO }}:${{ env.VERSION }} - - echo "推送分支标签镜像: ${{ env.REPO }}:${{ env.DOCKER_TAG_SUFFIX }}" - docker push ${{ env.REPO }}:${{ env.DOCKER_TAG_SUFFIX }} - - echo "镜像推送完成" - - # 步骤6: 调试 - 打印部署目标(不输出敏感信息) - - name: 🔍 调试 - 打印部署目标 - if: github.event_name == 'push' - run: | - echo "========== 部署目标调试 ==========" - echo "当前分支: ${{ github.ref_name }}" - echo "SSH_HOST: ${{ env.SSH_HOST }}" - echo "SSH_PORT: ${{ env.SSH_PORT }}" - echo "SSH_USER: ${{ env.SSH_USER }}" - echo "SSH认证方式: 私钥 (AWS)" - echo "DEPLOY_PATH: ${{ env.DEPLOY_PATH }}" - echo "=====================================" - - # 步骤7: 传输配置文件 - - name: 📂 传输配置文件 - if: github.event_name == 'push' - uses: appleboy/scp-action@v0.1.7 - with: - host: ${{ env.SSH_HOST }} - username: ${{ env.SSH_USER }} - key: ${{ env.SSH_KEY }} - port: ${{ env.SSH_PORT }} - source: "docker-compose.cloud.yml" - target: "/tmp/ppanel-deploy/" - - # 步骤8: 连接服务器更新、健康检查并按需回滚 - - name: 🚀 连接服务器更新并启动 - if: github.event_name == 'push' - uses: appleboy/ssh-action@v1.0.3 - with: - host: ${{ env.SSH_HOST }} - username: ${{ env.SSH_USER }} - key: ${{ env.SSH_KEY }} - port: ${{ env.SSH_PORT }} - timeout: 300s - command_timeout: 600s - script: | - set -e - - echo "连接服务器成功,开始部署..." - echo "部署目录: ${{ env.DEPLOY_PATH }}" - echo "部署标签: ${{ env.DOCKER_TAG_SUFFIX }}" - echo "登录用户: ${{ env.SSH_USER }}" - - HEALTHCHECK_URL="http://127.0.0.1:8080/v1/common/heartbeat" - NEW_TAG="${{ env.DOCKER_TAG_SUFFIX }}" - ROLLBACK_TAG="rollback-${{ env.VERSION }}" - SUDO="" - if [ "${{ github.ref_name }}" = "main" ]; then - SUDO="sudo" - fi - - docker_cmd() { - if [ -n "$SUDO" ]; then - sudo docker "$@" - else - docker "$@" - fi - } - - compose_with_tag() { - tag="$1" - shift - if [ -n "$SUDO" ]; then - sudo env PPANEL_SERVER_TAG="$tag" docker-compose -f docker-compose.cloud.yml "$@" - else - PPANEL_SERVER_TAG="$tag" docker-compose -f docker-compose.cloud.yml "$@" - fi - } - - write_previous_tag() { - if [ -n "$SUDO" ]; then - printf '%s\n' "${PREVIOUS_IMAGE_TAG:-}" | sudo tee .previous-ppanel-image-tag >/dev/null - else - printf '%s\n' "${PREVIOUS_IMAGE_TAG:-}" > .previous-ppanel-image-tag - fi - } - - health_check() { - attempt=1 - while [ "$attempt" -le 3 ]; do - if curl -sf "$HEALTHCHECK_URL"; then - echo - return 0 - fi - - echo "健康检查第 ${attempt}/3 次失败,10s 后重试..." - attempt=$((attempt + 1)) - sleep 10 - done - - return 1 - } - - if [ "${{ github.ref_name }}" = "main" ]; then - sudo mkdir -p ${{ env.DEPLOY_PATH }} - sudo cp /tmp/ppanel-deploy/docker-compose.cloud.yml ${{ env.DEPLOY_PATH }}/docker-compose.cloud.yml - else - mkdir -p ${{ env.DEPLOY_PATH }} - cp /tmp/ppanel-deploy/docker-compose.cloud.yml ${{ env.DEPLOY_PATH }}/docker-compose.cloud.yml - fi - - cd ${{ env.DEPLOY_PATH }} - - PREVIOUS_IMAGE_TAG="$(docker_cmd inspect --format '{{.Config.Image}}' ppanel-server 2>/dev/null || true)" - PREVIOUS_IMAGE_ID="$(docker_cmd inspect --format '{{.Image}}' ppanel-server 2>/dev/null || true)" - echo "上一版本镜像tag: ${PREVIOUS_IMAGE_TAG:-未发现}" - echo "上一版本镜像ID: ${PREVIOUS_IMAGE_ID:-未发现}" - write_previous_tag - - echo "📥 拉取镜像: ${{ env.REPO }}:${NEW_TAG}" - compose_with_tag "$NEW_TAG" pull ppanel-server - echo "🚀 启动服务..." - compose_with_tag "$NEW_TAG" up -d ppanel-server - - echo "🩺 部署后健康检查: ${HEALTHCHECK_URL}" - if health_check; then - docker_cmd image prune -f || true - echo "✅ 部署后健康检查通过" - echo "✅ 部署命令执行完成" - exit 0 - fi - - echo "❌ 部署后健康检查连续 3 次失败,开始回滚..." - if [ -n "$PREVIOUS_IMAGE_ID" ]; then - docker_cmd tag "$PREVIOUS_IMAGE_ID" "${{ env.REPO }}:${ROLLBACK_TAG}" - echo "回滚镜像tag: ${{ env.REPO }}:${ROLLBACK_TAG}" - compose_with_tag "$ROLLBACK_TAG" up -d ppanel-server - - echo "🩺 回滚后健康检查: ${HEALTHCHECK_URL}" - if health_check; then - echo "✅ 回滚后健康检查通过" - else - echo "❌ 回滚后健康检查仍失败" - fi - else - echo "未找到上一版本镜像ID,无法自动回滚" - fi - - docker_cmd image prune -f || true - exit 1 - - # 步骤9: TG通知 (成功) - - name: 📱 发送成功通知到Telegram - if: success() && github.event_name == 'push' - uses: appleboy/telegram-action@master - with: - token: ${{ env.TG_BOT_TOKEN }} - to: ${{ env.TG_CHAT_ID }} - message: | - ✅ 部署成功! - - 📦 项目: ${{ github.repository }} - 🌿 分支: ${{ github.ref_name }} - 📝 提交: ${{ github.sha }} - 👤 提交者: ${{ github.actor }} - 🕐 时间: ${{ github.event.head_commit.timestamp }} - - ${{ env.DEPLOY_ENV_LABEL }} - 🩺 健康检查: 通过 (http://127.0.0.1:8080/v1/common/heartbeat) - parse_mode: Markdown - - # 步骤10: TG通知 (失败) - - name: 📱 发送失败通知到Telegram - if: failure() && github.event_name == 'push' - uses: appleboy/telegram-action@master - with: - token: ${{ env.TG_BOT_TOKEN }} - to: ${{ env.TG_CHAT_ID }} - message: | - ❌ 部署失败! - - 📦 项目: ${{ github.repository }} - 🌿 分支: ${{ github.ref_name }} - 📝 提交: ${{ github.sha }} - 👤 提交者: ${{ github.actor }} - 🕐 时间: ${{ github.event.head_commit.timestamp }} - - 🩺 健康检查: 失败或未完成;若新版本健康检查连续 3 次失败,已自动尝试回滚并重新检查 - ⚠️ 请检查构建日志获取详细信息 - parse_mode: Markdown diff --git a/.github/environments/production.yml b/.github/environments/production.yml deleted file mode 100644 index 8e06538..0000000 --- a/.github/environments/production.yml +++ /dev/null @@ -1,27 +0,0 @@ -# Production Environment Configuration for GitHub Actions -# This file defines production-specific deployment settings - -environment: - name: production - url: https://api.ppanel.example.com - protection_rules: - - type: wait_timer - minutes: 5 - - type: reviewers - reviewers: - - "@admin-team" - - "@devops-team" - variables: - ENVIRONMENT: production - LOG_LEVEL: info - DEPLOY_TIMEOUT: 300 - -# Environment-specific secrets required: -# PRODUCTION_HOST - Production server hostname/IP -# PRODUCTION_USER - SSH username for production server -# PRODUCTION_SSH_KEY - SSH private key for production server -# PRODUCTION_PORT - SSH port (default: 22) -# PRODUCTION_URL - Application URL for health checks -# DATABASE_PASSWORD - Production database password -# REDIS_PASSWORD - Production Redis password -# JWT_SECRET - JWT secret key for production \ No newline at end of file diff --git a/.github/environments/staging.yml b/.github/environments/staging.yml deleted file mode 100644 index a62b4c4..0000000 --- a/.github/environments/staging.yml +++ /dev/null @@ -1,23 +0,0 @@ -# Staging Environment Configuration for GitHub Actions -# This file defines staging-specific deployment settings - -environment: - name: staging - url: https://staging-api.ppanel.example.com - protection_rules: - - type: wait_timer - minutes: 2 - variables: - ENVIRONMENT: staging - LOG_LEVEL: debug - DEPLOY_TIMEOUT: 180 - -# Environment-specific secrets required: -# STAGING_HOST - Staging server hostname/IP -# STAGING_USER - SSH username for staging server -# STAGING_SSH_KEY - SSH private key for staging server -# STAGING_PORT - SSH port (default: 22) -# STAGING_URL - Application URL for health checks -# DATABASE_PASSWORD - Staging database password -# REDIS_PASSWORD - Staging Redis password -# JWT_SECRET - JWT secret key for staging \ No newline at end of file diff --git a/.github/workflows/deploy-linux.yml b/.github/workflows/deploy-linux.yml deleted file mode 100644 index 83447ec..0000000 --- a/.github/workflows/deploy-linux.yml +++ /dev/null @@ -1,79 +0,0 @@ -name: Build Linux Binary - -on: - push: - branches: [ main, master ] - tags: - - 'v*' - workflow_dispatch: - inputs: - version: - description: 'Version to build (leave empty for auto)' - required: false - type: string - -permissions: - contents: write - -jobs: - build: - name: Build Linux Binary - runs-on: ario-server - - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Setup Go - uses: actions/setup-go@v5 - with: - go-version: '1.23.3' - cache: true - - - name: Build - env: - CGO_ENABLED: 0 - GOOS: linux - GOARCH: amd64 - run: | - VERSION=${{ github.event.inputs.version }} - if [ -z "$VERSION" ]; then - VERSION=$(git describe --tags --always --dirty) - fi - - echo "Building ppanel-server $VERSION" - BUILD_TIME=$(date +"%Y-%m-%d_%H:%M:%S") - go build -ldflags="-w -s -X github.com/perfect-panel/server/pkg/constant.Version=$VERSION -X github.com/perfect-panel/server/pkg/constant.BuildTime=$BUILD_TIME" -o ppanel-server ./ppanel.go - tar -czf ppanel-server-${VERSION}-linux-amd64.tar.gz ppanel-server - sha256sum ppanel-server ppanel-server-${VERSION}-linux-amd64.tar.gz > checksum.txt - - - name: Upload artifacts - uses: actions/upload-artifact@v4 - with: - name: ppanel-server-linux-amd64 - path: | - ppanel-server - ppanel-server-*-linux-amd64.tar.gz - checksum.txt - - - name: Create Release - if: startsWith(github.ref, 'refs/tags/') - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - VERSION=${GITHUB_REF#refs/tags/} - - # Check if release exists - if gh release view $VERSION >/dev/null 2>&1; then - echo "Release $VERSION already exists, deleting old assets..." - # Delete existing assets if they exist - gh release delete-asset $VERSION ppanel-server-${VERSION}-linux-amd64.tar.gz --yes 2>/dev/null || true - gh release delete-asset $VERSION checksum.txt --yes 2>/dev/null || true - else - echo "Creating new release $VERSION..." - gh release create $VERSION --title "PPanel Server $VERSION" --notes "Release $VERSION" - fi - - # Upload assets (will overwrite if --clobber is supported, otherwise will fail gracefully) - echo "Uploading assets..." - gh release upload $VERSION ppanel-server-${VERSION}-linux-amd64.tar.gz checksum.txt --clobber diff --git a/.gitignore b/.gitignore index ce9f7ff..ed79409 100644 --- a/.gitignore +++ b/.gitignore @@ -26,6 +26,13 @@ Thumbs.db *.crt *.key *.pem +*.pub +*id_rsa* +*id_ed25519* +*_bak +*.go_bak +deploy/**/keys/ +deliverables/ # ==================== 日志 ==================== *.log @@ -70,6 +77,7 @@ script/*.sh # Codex local configuration .codex/ +.codex-tmp/ # Claude Flow runtime data .claude-flow/data/ diff --git a/.goreleaser.yaml b/.goreleaser.yaml deleted file mode 100644 index fa6d223..0000000 --- a/.goreleaser.yaml +++ /dev/null @@ -1,66 +0,0 @@ -project_name: ppanel -version: 1 -release: - prerelease: auto -builds: - - # If true, skip the build. - # Useful for library projects. - # Default is false - skip: true - -changelog: - # Set it to true if you wish to skip the changelog generation. - # This may result in an empty release notes on GitHub/GitLab/Gitea. - disable: false - - # Changelog generation implementation to use. - # - # Valid options are: - # - `git`: uses `git log`; - # - `github`: uses the compare GitHub API, appending the author login to the changelog. - # - `gitlab`: uses the compare GitLab API, appending the author name and email to the changelog. - # - `github-native`: uses the GitHub release notes generation API, disables the groups feature. - # - # Defaults to `git`. - use: github - - # Sorts the changelog by the commit's messages. - # Could either be asc, desc or empty - # Default is empty - sort: asc - - # Format to use for commit formatting. - # Only available when use is one of `github`, `gitea`, or `gitlab`. - # - # Default: '{{ .SHA }}: {{ .Message }} ({{ with .AuthorUsername }}@{{ . }}{{ else }}{{ .AuthorName }} <{{ .AuthorEmail }}>{{ end }})'. - # Extra template fields: `SHA`, `Message`, `AuthorName`, `AuthorEmail`, and - # `AuthorUsername`. - format: "{{ .Message }}" - - # Group commits messages by given regex and title. - # Order value defines the order of the groups. - # Proving no regex means all commits will be grouped under the default group. - # Groups are disabled when using github-native, as it already groups things by itself. - # - # Default is no groups. - groups: - - title: "✨ Features" - regexp: "^.*feat[(\\w)]*:+.*$" - order: 0 - - title: "🐛 Bug Fixes" - regexp: "^.*fix[(\\w)]*:+.*$" - order: 1 - - title: "🎫 Chores" - regexp: "^.*chore[(\\w)]*:+.*$" - order: 2 - - title: "🔨 Refactor" - regexp: "^.*refactor[(\\w)]*:+.*$" - order: 3 - - title: "🔧 Build" - regexp: "^.*?(ci)(\\(.+\\))??!?:.+$" - order: 4 - - title: "📝 Documentation" - regexp: "^.*?docs?(\\(.+\\))??!?:.+$" - order: 5 - - title: "✨ Others" - order: 999 diff --git a/deliverables/ec2-ssh/README.txt b/deliverables/ec2-ssh/README.txt deleted file mode 100644 index 114b4ae..0000000 --- a/deliverables/ec2-ssh/README.txt +++ /dev/null @@ -1,20 +0,0 @@ -EC2 SSH 连接资料 - -服务器名称: hifast-hk-app-01 -公网 IP: 43.198.248.161 -登录用户: ubuntu - -私钥文件: -- hifast-hk-app-01-reset - -公钥文件: -- hifast-hk-app-01-reset.pub - -连接命令: -ssh -i hifast-hk-app-01-reset ubuntu@43.198.248.161 - -如果在 Mac / Linux 上使用,先执行: -chmod 600 hifast-hk-app-01-reset - -如果要给别人使用,只需要把私钥文件 hifast-hk-app-01-reset 发给对方即可。 -出于安全考虑,建议通过安全渠道传输,并在后续需要时重新轮换密钥。 diff --git a/deliverables/ec2-ssh/hifast-hk-app-01-reset b/deliverables/ec2-ssh/hifast-hk-app-01-reset deleted file mode 100644 index 28b76e8..0000000 --- a/deliverables/ec2-ssh/hifast-hk-app-01-reset +++ /dev/null @@ -1,8 +0,0 @@ ------BEGIN OPENSSH PRIVATE KEY----- -b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW -QyNTUxOQAAACDb6msDqmSHLv0mWgCP4vfjQ3A552qv95uQdsH94RnoCgAAAKjy5KDa8uSg -2gAAAAtzc2gtZWQyNTUxOQAAACDb6msDqmSHLv0mWgCP4vfjQ3A552qv95uQdsH94RnoCg -AAAEDwSb0b/0S6Tw8Od5hAtIKqt1JvomqQQS44Ty3xL+FjPtvqawOqZIcu/SZaAI/i9+ND -cDnnaq/3m5B2wf3hGegKAAAAIWhpZmFzdC1oay1hcHAtMDEtcmVzZXQtMjAyNi0wNS0xMA -ECAwQ= ------END OPENSSH PRIVATE KEY----- diff --git a/deliverables/ec2-ssh/hifast-hk-app-01-reset.pub b/deliverables/ec2-ssh/hifast-hk-app-01-reset.pub deleted file mode 100644 index 7a96127..0000000 --- a/deliverables/ec2-ssh/hifast-hk-app-01-reset.pub +++ /dev/null @@ -1 +0,0 @@ -ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINvqawOqZIcu/SZaAI/i9+NDcDnnaq/3m5B2wf3hGegK hifast-hk-app-01-reset-2026-05-10 diff --git a/deploy/aws/ap-northeast-1/configs/resource-inventory.current.md b/deploy/aws/ap-northeast-1/configs/resource-inventory.current.md index 628847e..1c21dff 100644 --- a/deploy/aws/ap-northeast-1/configs/resource-inventory.current.md +++ b/deploy/aws/ap-northeast-1/configs/resource-inventory.current.md @@ -111,8 +111,7 @@ - EIP allocation ID: `eipalloc-038b32d5c0119accf` - EIP association ID: `eipassoc-09184aa9161b6a4d9` - Status: `running` - - SSH recovery private key: `deploy/aws/ap-northeast-1/keys/ppanel-jp-recovery` - - SSH recovery public key: `deploy/aws/ap-northeast-1/keys/ppanel-jp-recovery.pub` + - SSH recovery key material: not stored in this repository; keep any recovery keys in an approved secret manager or other secure channel. - RDS subnet group: - Name: `ppanel-jp-rds-subnet-group` - VPC: `vpc-0846b23b4a7d64eac` diff --git a/deploy/aws/ap-northeast-1/keys/ppanel-jp-recovery b/deploy/aws/ap-northeast-1/keys/ppanel-jp-recovery deleted file mode 100644 index 5c82884..0000000 --- a/deploy/aws/ap-northeast-1/keys/ppanel-jp-recovery +++ /dev/null @@ -1,7 +0,0 @@ ------BEGIN OPENSSH PRIVATE KEY----- -b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW -QyNTUxOQAAACBsJxZDjKvaIdVjer3QMHRYw43wkVnzHurA2TQqHlr1YwAAAKBaQXT3WkF0 -9wAAAAtzc2gtZWQyNTUxOQAAACBsJxZDjKvaIdVjer3QMHRYw43wkVnzHurA2TQqHlr1Yw -AAAEArWQWWwPoJp+za5JhSnrE0Pw1/TtqWRrdY5e8hULqYDGwnFkOMq9oh1WN6vdAwdFjD -jfCRWfMe6sDZNCoeWvVjAAAAF0FwcGxlQE1hY0Jvb2stUHJvLmxvY2FsAQIDBAUG ------END OPENSSH PRIVATE KEY----- diff --git a/deploy/aws/ap-northeast-1/keys/ppanel-jp-recovery.pub b/deploy/aws/ap-northeast-1/keys/ppanel-jp-recovery.pub deleted file mode 100644 index 60be616..0000000 --- a/deploy/aws/ap-northeast-1/keys/ppanel-jp-recovery.pub +++ /dev/null @@ -1 +0,0 @@ -ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGwnFkOMq9oh1WN6vdAwdFjDjfCRWfMe6sDZNCoeWvVj Apple@MacBook-Pro.local diff --git a/docker-compose.yml b/docker-compose.yml index c2b3225..3bc2ced 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,5 +1,3 @@ -version: '3' - services: ppanel: container_name: ppanel-server diff --git a/queue/logic/order/activateOrderLogic.go_bak b/queue/logic/order/activateOrderLogic.go_bak deleted file mode 100644 index f57f57f..0000000 --- a/queue/logic/order/activateOrderLogic.go_bak +++ /dev/null @@ -1,675 +0,0 @@ -package orderLogic - -import ( - "context" - "encoding/json" - "fmt" - "strconv" - "time" - - "github.com/perfect-panel/server/pkg/constant" - - "github.com/perfect-panel/server/pkg/logger" - - tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5" - "github.com/google/uuid" - "github.com/hibiken/asynq" - "github.com/perfect-panel/server/internal/config" - "github.com/perfect-panel/server/internal/logic/telegram" - "github.com/perfect-panel/server/internal/model/order" - "github.com/perfect-panel/server/internal/model/user" - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/pkg/tool" - "github.com/perfect-panel/server/pkg/uuidx" - "github.com/perfect-panel/server/queue/types" - "gorm.io/gorm" -) - -const ( - Subscribe = 1 - Renewal = 2 - ResetTraffic = 3 - Recharge = 4 -) - -type ActivateOrderLogic struct { - svc *svc.ServiceContext -} - -func NewActivateOrderLogic(svc *svc.ServiceContext) *ActivateOrderLogic { - return &ActivateOrderLogic{ - svc: svc, - } -} - -func (l *ActivateOrderLogic) ProcessTask(ctx context.Context, task *asynq.Task) error { - payload := types.ForthwithActivateOrderPayload{} - if err := json.Unmarshal(task.Payload(), &payload); err != nil { - logger.WithContext(ctx).Error("[ActivateOrderLogic] Unmarshal payload failed", - logger.Field("error", err.Error()), - logger.Field("payload", string(task.Payload())), - ) - return nil - } - // Find order by order no - orderInfo, err := l.svc.OrderModel.FindOneByOrderNo(ctx, payload.OrderNo) - if err != nil { - logger.WithContext(ctx).Error("[ActivateOrderLogic] Find order failed", - logger.Field("error", err.Error()), - logger.Field("order_no", payload.OrderNo), - ) - return nil - } - // 1: Pending, 2: Paid, 3:Close, 4: Failed, 5:Finished - if orderInfo.Status != 2 { - logger.WithContext(ctx).Error("[ActivateOrderLogic] Order status error", - logger.Field("order_no", orderInfo.OrderNo), - logger.Field("status", orderInfo.Status), - ) - return nil - } - switch orderInfo.Type { - case Subscribe: - err = l.NewPurchase(ctx, orderInfo) - case Renewal: - err = l.Renewal(ctx, orderInfo) - case ResetTraffic: - err = l.ResetTraffic(ctx, orderInfo) - case Recharge: - err = l.Recharge(ctx, orderInfo) - default: - logger.WithContext(ctx).Error("[ActivateOrderLogic] Order type is invalid", logger.Field("type", orderInfo.Type)) - return nil - } - if err != nil { - logger.WithContext(ctx).Error("[ActivateOrderLogic] Process task failed", logger.Field("error", err.Error())) - return nil - } - // if coupon is not empty - if orderInfo.Coupon != "" { - // update coupon status - err = l.svc.CouponModel.UpdateCount(ctx, orderInfo.Coupon) - if err != nil { - logger.WithContext(ctx).Error("[ActivateOrderLogic] Update coupon status failed", - logger.Field("error", err.Error()), - logger.Field("coupon", orderInfo.Coupon), - ) - } - } - // update order status - orderInfo.Status = 5 - err = l.svc.OrderModel.Update(ctx, orderInfo) - if err != nil { - logger.WithContext(ctx).Error("[ActivateOrderLogic] Update order status failed", - logger.Field("error", err.Error()), - logger.Field("order_no", orderInfo.OrderNo), - ) - } - - return nil -} - -// NewPurchase New purchase -func (l *ActivateOrderLogic) NewPurchase(ctx context.Context, orderInfo *order.Order) error { - var userInfo *user.User - var err error - if orderInfo.UserId != 0 { - // find user by user id - userInfo, err = l.svc.UserModel.FindOne(ctx, orderInfo.UserId) - if err != nil { - logger.WithContext(ctx).Error("[ActivateOrderLogic] Find user failed", - logger.Field("error", err.Error()), - logger.Field("user_id", orderInfo.UserId), - ) - return err - } - } else { - // If User ID is 0, it means that the order is a guest order, need to create a new user - // query info with redis - cacheKey := fmt.Sprintf(constant.TempOrderCacheKey, orderInfo.OrderNo) - data, err := l.svc.Redis.Get(ctx, cacheKey).Result() - if err != nil { - logger.WithContext(ctx).Error("[ActivateOrderLogic] Get temp order cache failed", - logger.Field("error", err.Error()), - logger.Field("cache_key", cacheKey), - ) - return err - } - var tempOrder constant.TemporaryOrderInfo - if err = json.Unmarshal([]byte(data), &tempOrder); err != nil { - logger.WithContext(ctx).Errorw("[ActivateOrderLogic] Unmarshal temp order failed", - logger.Field("error", err.Error()), - ) - return err - } - // create user - - userInfo = &user.User{ - Password: tool.EncodePassWord(tempOrder.Password), - AuthMethods: []user.AuthMethods{ - { - AuthType: tempOrder.AuthType, - AuthIdentifier: tempOrder.Identifier, - }, - }, - } - err = l.svc.UserModel.Transaction(ctx, func(tx *gorm.DB) error { - // Save user information - if err := tx.Save(userInfo).Error; err != nil { - return err - } - // Generate ReferCode - userInfo.ReferCode = uuidx.UserInviteCode(userInfo.Id) - // Update ReferCode - if err := tx.Model(&user.User{}).Where("id = ?", userInfo.Id).Update("refer_code", userInfo.ReferCode).Error; err != nil { - return err - } - orderInfo.UserId = userInfo.Id - return tx.Model(&order.Order{}).Where("order_no = ?", orderInfo.OrderNo).Update("user_id", userInfo.Id).Error - }) - if err != nil { - logger.WithContext(ctx).Error("[ActivateOrderLogic] Create user failed", - logger.Field("error", err.Error()), - ) - return err - } - - if tempOrder.InviteCode != "" { - // find referer by refer code - referer, err := l.svc.UserModel.FindOneByReferCode(ctx, tempOrder.InviteCode) - if err != nil { - logger.WithContext(ctx).Error("[ActivateOrderLogic] Find referer failed", - logger.Field("error", err.Error()), - logger.Field("refer_code", tempOrder.InviteCode), - ) - } else { - userInfo.RefererId = referer.Id - err = l.svc.UserModel.Update(ctx, userInfo) - if err != nil { - logger.WithContext(ctx).Error("[ActivateOrderLogic] Update user referer failed", - logger.Field("error", err.Error()), - logger.Field("user_id", userInfo.Id), - ) - } - } - } - - logger.WithContext(ctx).Info("[ActivateOrderLogic] Create guest user success", logger.Field("user_id", userInfo.Id), logger.Field("Identifier", tempOrder.Identifier), logger.Field("AuthType", tempOrder.AuthType)) - } - // find subscribe by id - sub, err := l.svc.SubscribeModel.FindOne(ctx, orderInfo.SubscribeId) - if err != nil { - logger.WithContext(ctx).Errorw("[ActivateOrderLogic] Find subscribe failed", - logger.Field("error", err.Error()), - logger.Field("subscribe_id", orderInfo.SubscribeId), - ) - return err - } - // create user subscribe - now := time.Now() - - userSub := user.Subscribe{ - Id: 0, - UserId: orderInfo.UserId, - OrderId: orderInfo.Id, - SubscribeId: orderInfo.SubscribeId, - StartTime: now, - ExpireTime: tool.AddTime(sub.UnitTime, orderInfo.Quantity, now), - Traffic: sub.Traffic, - Download: 0, - Upload: 0, - Token: uuidx.SubscribeToken(orderInfo.OrderNo), - UUID: uuid.New().String(), - Status: 1, - } - err = l.svc.UserModel.InsertSubscribe(ctx, &userSub) - - if err != nil { - logger.WithContext(ctx).Error("[ActivateOrderLogic] Insert user subscribe failed", - logger.Field("error", err.Error()), - ) - return err - } - // handler commission - if userInfo.RefererId != 0 && - l.svc.Config.Invite.ReferralPercentage != 0 && - (!l.svc.Config.Invite.OnlyFirstPurchase || orderInfo.IsNew) { - referer, err := l.svc.UserModel.FindOne(ctx, userInfo.RefererId) - if err != nil { - logger.WithContext(ctx).Error("[ActivateOrderLogic] Find referer failed", - logger.Field("error", err.Error()), - logger.Field("referer_id", userInfo.RefererId), - ) - goto updateCache - } - // calculate commission - amount := float64(orderInfo.Price) * (float64(l.svc.Config.Invite.ReferralPercentage) / 100) - referer.Commission += int64(amount) - err = l.svc.UserModel.Update(ctx, referer) - if err != nil { - logger.WithContext(ctx).Error("[ActivateOrderLogic] Update referer commission failed", - logger.Field("error", err.Error()), - ) - goto updateCache - } - // create commission log - commissionLog := user.CommissionLog{ - UserId: referer.Id, - OrderNo: orderInfo.OrderNo, - Amount: int64(amount), - } - err = l.svc.UserModel.InsertCommissionLog(ctx, &commissionLog) - if err != nil { - logger.WithContext(ctx).Error("[ActivateOrderLogic] Insert commission log failed", - logger.Field("error", err.Error()), - ) - } - err = l.svc.UserModel.UpdateUserCache(ctx, referer) - if err != nil { - logger.WithContext(ctx).Errorw("[ActivateOrderLogic] Update referer cache", logger.Field("error", err.Error()), logger.Field("user_id", referer.Id)) - } - } -updateCache: - for _, id := range tool.StringToInt64Slice(sub.Server) { - cacheKey := fmt.Sprintf("%s%d", config.ServerUserListCacheKey, id) - err = l.svc.Redis.Del(ctx, cacheKey).Err() - if err != nil { - logger.WithContext(ctx).Error("[ActivateOrderLogic] Del server user list cache failed", - logger.Field("error", err.Error()), - logger.Field("cache_key", cacheKey), - ) - } - } - data, err := l.svc.ServerModel.FindServerListByGroupIds(ctx, tool.StringToInt64Slice(sub.ServerGroup)) - if err != nil { - logger.WithContext(ctx).Error("[ActivateOrderLogic] Find server list failed", logger.Field("error", err.Error())) - return err - } - for _, item := range data { - cacheKey := fmt.Sprintf("%s%d", config.ServerUserListCacheKey, item.Id) - err = l.svc.Redis.Del(ctx, cacheKey).Err() - if err != nil { - logger.WithContext(ctx).Error("[ActivateOrderLogic] Del server user list cache failed", - logger.Field("error", err.Error()), - logger.Field("cache_key", cacheKey), - ) - } - } - userTelegramChatId, ok := findTelegram(userInfo) - - // sendMessage To Telegram - if ok { - text, err := tool.RenderTemplateToString(telegram.PurchaseNotify, map[string]string{ - "OrderNo": orderInfo.OrderNo, - "SubscribeName": sub.Name, - "OrderAmount": fmt.Sprintf("%.2f", float64(orderInfo.Price)/100), - "ExpireTime": userSub.ExpireTime.Format("2006-01-02 15:04:05"), - }) - if err != nil { - logger.WithContext(ctx).Error("[ActivateOrderLogic] Render template failed", - logger.Field("error", err.Error()), - ) - } - l.sendUserNotifyWithTelegram(userTelegramChatId, text) - } - // send message to admin - text, err := tool.RenderTemplateToString(telegram.AdminOrderNotify, map[string]string{ - "OrderNo": orderInfo.OrderNo, - "TradeNo": orderInfo.TradeNo, - "SubscribeName": sub.Name, - //"UserEmail": userInfo.Email, - "OrderAmount": fmt.Sprintf("%.2f", float64(orderInfo.Price)/100), - "OrderStatus": "已支付", - "OrderTime": orderInfo.CreatedAt.Format("2006-01-02 15:04:05"), - "PaymentMethod": orderInfo.Method, - }) - if err != nil { - logger.WithContext(ctx).Error("[ActivateOrderLogic] Render AdminOrderNotify template failed", - logger.Field("error", err.Error()), - ) - } - l.sendAdminNotifyWithTelegram(ctx, text) - logger.WithContext(ctx).Info("[ActivateOrderLogic] Insert user subscribe success") - return nil -} - -// Renewal Renewal -func (l *ActivateOrderLogic) Renewal(ctx context.Context, orderInfo *order.Order) error { - // find user by user id - userInfo, err := l.svc.UserModel.FindOne(ctx, orderInfo.UserId) - if err != nil { - logger.WithContext(ctx).Error("[ActivateOrderLogic] Find user failed", - logger.Field("error", err.Error()), - logger.Field("user_id", orderInfo.UserId), - ) - return err - } - // find user subscribe by subscribe token - userSub, err := l.svc.UserModel.FindOneSubscribeByToken(ctx, orderInfo.SubscribeToken) - if err != nil { - logger.WithContext(ctx).Error("[ActivateOrderLogic] Find user subscribe failed", - logger.Field("error", err.Error()), - logger.Field("order_id", orderInfo.Id), - ) - return err - } - // find subscribe by id - sub, err := l.svc.SubscribeModel.FindOne(ctx, orderInfo.SubscribeId) - if err != nil { - logger.WithContext(ctx).Error("[ActivateOrderLogic] Find subscribe failed", - logger.Field("error", err.Error()), - logger.Field("subscribe_id", orderInfo.SubscribeId), - logger.Field("order_id", orderInfo.Id), - ) - return err - } - now := time.Now() - if userSub.ExpireTime.Before(now) { - userSub.ExpireTime = now - } - - // Check whether traffic reset on renewal is enabled - if sub.RenewalReset != nil && *sub.RenewalReset { - userSub.Download = 0 - userSub.Upload = 0 - } - if userSub.FinishedAt != nil { - userSub.FinishedAt = nil - } - - userSub.ExpireTime = tool.AddTime(sub.UnitTime, orderInfo.Quantity, userSub.ExpireTime) - userSub.Status = 1 - // update user subscribe - err = l.svc.UserModel.UpdateSubscribe(ctx, userSub) - if err != nil { - logger.WithContext(ctx).Error("[ActivateOrderLogic] Update user subscribe failed", - logger.Field("error", err.Error()), - ) - return err - } - // handler commission - if userInfo.RefererId != 0 && - l.svc.Config.Invite.ReferralPercentage != 0 && - !l.svc.Config.Invite.OnlyFirstPurchase { - referer, err := l.svc.UserModel.FindOne(ctx, userInfo.RefererId) - if err != nil { - logger.WithContext(ctx).Error("[ActivateOrderLogic] Find referer failed", - logger.Field("error", err.Error()), - logger.Field("referer_id", userInfo.RefererId), - ) - goto sendMessage - } - // calculate commission - amount := float64(orderInfo.Price) * (float64(l.svc.Config.Invite.ReferralPercentage) / 100) - referer.Commission += int64(amount) - err = l.svc.UserModel.Update(ctx, referer) - if err != nil { - logger.WithContext(ctx).Error("[ActivateOrderLogic] Update referer commission failed", - logger.Field("error", err.Error()), - ) - goto sendMessage - } - // create commission log - commissionLog := user.CommissionLog{ - UserId: referer.Id, - OrderNo: orderInfo.OrderNo, - Amount: int64(amount), - } - err = l.svc.UserModel.InsertCommissionLog(ctx, &commissionLog) - if err != nil { - logger.WithContext(ctx).Error("[ActivateOrderLogic] Insert commission log failed", - logger.Field("error", err.Error()), - ) - } - err = l.svc.UserModel.UpdateUserCache(ctx, referer) - if err != nil { - logger.WithContext(ctx).Errorw("[ActivateOrderLogic] Update referer cache", logger.Field("error", err.Error()), logger.Field("user_id", referer.Id)) - } - } - -sendMessage: - userTelegramChatId, ok := findTelegram(userInfo) - // SendMessage To Telegram - if ok { - text, err := tool.RenderTemplateToString(telegram.RenewalNotify, map[string]string{ - "OrderNo": orderInfo.OrderNo, - "SubscribeName": sub.Name, - "OrderAmount": fmt.Sprintf("%.2f", float64(orderInfo.Price)/100), - "ExpireTime": userSub.ExpireTime.Format("2006-01-02 15:04:05"), - }) - if err != nil { - logger.WithContext(ctx).Error("[ActivateOrderLogic] Render template failed", - logger.Field("error", err.Error()), - ) - } - l.sendUserNotifyWithTelegram(userTelegramChatId, text) - } - - // send message to admin - text, err := tool.RenderTemplateToString(telegram.AdminOrderNotify, map[string]string{ - "OrderNo": orderInfo.OrderNo, - "TradeNo": orderInfo.TradeNo, - "SubscribeName": sub.Name, - //"UserEmail": userInfo.Email, - "OrderAmount": fmt.Sprintf("%.2f", float64(orderInfo.Price)/100), - "OrderStatus": "已支付", - "OrderTime": orderInfo.CreatedAt.Format("2006-01-02 15:04:05"), - "PaymentMethod": orderInfo.Method, - }) - if err != nil { - logger.WithContext(ctx).Error("[ActivateOrderLogic] Render AdminOrderNotify template failed", - logger.Field("error", err.Error()), - ) - } - l.sendAdminNotifyWithTelegram(ctx, text) - return nil -} - -// ResetTraffic Reset traffic -func (l *ActivateOrderLogic) ResetTraffic(ctx context.Context, orderInfo *order.Order) error { - // find user by user id - userInfo, err := l.svc.UserModel.FindOne(ctx, orderInfo.UserId) - if err != nil { - logger.WithContext(ctx).Error("[ActivateOrderLogic] Find user failed", - logger.Field("error", err.Error()), - logger.Field("user_id", orderInfo.UserId), - ) - return err - } - // Generate a Subscribe Token through orderNo - // find user subscribe by subscribe token - userSub, err := l.svc.UserModel.FindOneSubscribeByToken(ctx, orderInfo.SubscribeToken) - if err != nil { - logger.WithContext(ctx).Error("[ActivateOrderLogic] Find user subscribe failed", - logger.Field("error", err.Error()), - logger.Field("order_id", orderInfo.Id), - ) - return err - } - userSub.Download = 0 - userSub.Upload = 0 - userSub.Status = 1 - // update user subscribe - err = l.svc.UserModel.UpdateSubscribe(ctx, userSub) - if err != nil { - logger.WithContext(ctx).Error("[ActivateOrderLogic] Update user subscribe failed", - logger.Field("error", err.Error()), - ) - return err - } - sub, err := l.svc.SubscribeModel.FindOne(ctx, userSub.SubscribeId) - if err != nil { - logger.WithContext(ctx).Error("[ActivateOrderLogic] Find subscribe failed", - logger.Field("error", err.Error()), - logger.Field("subscribe_id", userSub.SubscribeId), - ) - return err - } - userTelegramChatId, ok := findTelegram(userInfo) - // SendMessage To Telegram - if ok { - text, err := tool.RenderTemplateToString(telegram.ResetTrafficNotify, map[string]string{ - "OrderNo": orderInfo.OrderNo, - "SubscribeName": sub.Name, - "ResetTime": time.Now().Format("2006-01-02 15:04:05"), - "ExpireTime": userSub.ExpireTime.Format("2006-01-02 15:04:05"), - }) - if err != nil { - logger.WithContext(ctx).Error("[ActivateOrderLogic] Render template failed", - logger.Field("error", err.Error()), - ) - } - l.sendUserNotifyWithTelegram(userTelegramChatId, text) - } - - // send message to admin - text, err := tool.RenderTemplateToString(telegram.AdminOrderNotify, map[string]string{ - "OrderNo": orderInfo.OrderNo, - "TradeNo": orderInfo.TradeNo, - "SubscribeName": "流量重置", - "OrderAmount": fmt.Sprintf("%.2f", float64(orderInfo.Price)/100), - "OrderStatus": "已支付", - "OrderTime": orderInfo.CreatedAt.Format("2006-01-02 15:04:05"), - "PaymentMethod": orderInfo.Method, - }) - if err != nil { - logger.WithContext(ctx).Error("[ActivateOrderLogic] Render AdminOrderNotify template failed", - logger.Field("error", err.Error()), - ) - } - l.sendAdminNotifyWithTelegram(ctx, text) - return nil -} - -// Recharge Recharge to user -func (l *ActivateOrderLogic) Recharge(ctx context.Context, orderInfo *order.Order) error { - // find user by user id - userInfo, err := l.svc.UserModel.FindOne(ctx, orderInfo.UserId) - if err != nil { - logger.WithContext(ctx).Error("[ActivateOrderLogic] Find user failed", - logger.Field("error", err.Error()), - logger.Field("user_id", orderInfo.UserId), - ) - return err - } - userInfo.Balance += orderInfo.Price - // update user - err = l.svc.DB.Transaction(func(tx *gorm.DB) error { - err = l.svc.UserModel.Update(ctx, userInfo, tx) - if err != nil { - logger.WithContext(ctx).Error("[ActivateOrderLogic] Update user failed", - logger.Field("error", err.Error()), - ) - return err - } - // Create Balance Log - balanceLog := user.BalanceLog{ - UserId: orderInfo.UserId, - Amount: orderInfo.Price, - Type: 1, - OrderId: orderInfo.Id, - Balance: userInfo.Balance, - } - err = l.svc.UserModel.InsertBalanceLog(ctx, &balanceLog, tx) - if err != nil { - logger.WithContext(ctx).Error("[ActivateOrderLogic] Insert balance log failed", - logger.Field("error", err.Error()), - ) - return err - } - - return nil - }) - if err != nil { - logger.WithContext(ctx).Error("[ActivateOrderLogic] Database transaction failed", - logger.Field("error", err.Error()), - ) - return err - } - userTelegramChatId, ok := findTelegram(userInfo) - // SendMessage To Telegram - if ok { - text, err := tool.RenderTemplateToString(telegram.RechargeNotify, map[string]string{ - "OrderAmount": fmt.Sprintf("%.2f", float64(orderInfo.Price)/100), - "PaymentMethod": orderInfo.Method, - "Time": orderInfo.CreatedAt.Format("2006-01-02 15:04:05"), - "Balance": fmt.Sprintf("%.2f", float64(userInfo.Balance)/100), - }) - if err != nil { - logger.WithContext(ctx).Error("[ActivateOrderLogic] Render template failed", - logger.Field("error", err.Error()), - ) - } - l.sendUserNotifyWithTelegram(userTelegramChatId, text) - } - // send message to admin - text, err := tool.RenderTemplateToString(telegram.AdminOrderNotify, map[string]string{ - "OrderNo": orderInfo.OrderNo, - "TradeNo": orderInfo.TradeNo, - "OrderAmount": fmt.Sprintf("%.2f", float64(orderInfo.Price)/100), - "SubscribeName": "余额充值", - "OrderStatus": "已支付", - "OrderTime": orderInfo.CreatedAt.Format("2006-01-02 15:04:05"), - "PaymentMethod": orderInfo.Method, - }) - if err != nil { - logger.WithContext(ctx).Error("[ActivateOrderLogic] Render AdminOrderNotify template failed", - logger.Field("error", err.Error()), - ) - } - l.sendAdminNotifyWithTelegram(ctx, text) - return nil -} - -// sendUserNotifyWithTelegram send message to user -func (l *ActivateOrderLogic) sendUserNotifyWithTelegram(chatId int64, text string) { - msg := tgbotapi.NewMessage(chatId, text) - msg.ParseMode = "markdown" - _, err := l.svc.TelegramBot.Send(msg) - if err != nil { - logger.Error("[ActivateOrderLogic] Send telegram user message failed", - logger.Field("error", err.Error()), - ) - } -} - -// sendAdminNotifyWithTelegram send message to admin -func (l *ActivateOrderLogic) sendAdminNotifyWithTelegram(ctx context.Context, text string) { - admins, err := l.svc.UserModel.QueryAdminUsers(ctx) - if err != nil { - logger.WithContext(ctx).Error("[ActivateOrderLogic] Query admin users failed", - logger.Field("error", err.Error()), - ) - return - } - for _, admin := range admins { - telegramId, ok := findTelegram(admin) - if !ok { - continue - } - msg := tgbotapi.NewMessage(telegramId, text) - msg.ParseMode = "markdown" - _, err := l.svc.TelegramBot.Send(msg) - if err != nil { - logger.WithContext(ctx).Error("[ActivateOrderLogic] Send telegram admin message failed", - logger.Field("error", err.Error()), - ) - } - } -} - -// findTelegram find user telegram id -func findTelegram(u *user.User) (int64, bool) { - for _, item := range u.AuthMethods { - if item.AuthType == "telegram" { - // string to int64 - parseInt, err := strconv.ParseInt(item.AuthIdentifier, 10, 64) - if err != nil { - return 0, false - } - return parseInt, true - } - - } - return 0, false -} diff --git a/迁移到命令.txt b/迁移到命令.txt deleted file mode 100644 index 780fb22..0000000 --- a/迁移到命令.txt +++ /dev/null @@ -1,44 +0,0 @@ -导出数据库: -mysqldump --socket=/var/run/mysqld/mysqld.sock -uroot -p --single-transaction --routines --triggers --events --set-gtid-purged=OFF --source-data=2 --no-tablespaces hifast > /root/data/hifast-final-0515.sql - -jpcV41ppanel - -gzip -1 /root/hifast-final-0515.sql - - - - - -导出redis: -redis-cli -a '0BVz9XOHf7KUfEuoFJRK-dURdKUGFiZ8QeaHpysHnKeKhLskZb55HPK121lFsKtr' BGSAVE -sleep 5 -cp /var/lib/redis/dump.rdb /root/data/redis-backup-0515.rdb - - -导入数据库: -gunzip -c /root/hifast-final-0515.sql.gz | docker exec -i ppanel-mysql mysql -uroot -p'jpcV41ppanel' hifast - - -导入redis: -docker stop ppanel-redis -docker cp /root/data/redis-backup-0515.rdb ppanel-redis:/data/dump.rdb -docker start ppanel-redis -docker exec ppanel-redis redis-cli -a 'hifast67yj' DBSIZE - - - -docker stop ppanel-redis || true -docker rm -f ppanel-redis - -rm -f /root/data/dump.rdb -rm -rf /root/data/appendonlydir -rm -f /root/data/appendonly.aof* -mkdir -p /root/data - -docker pull redis:8.6.3 -docker run -d \ - --name ppanel-redis \ - --restart always \ - -p 6379:6379 \ - redis:8.6.3 \ - redis-server --requirepass 'hifast67yj'