This commit is contained in:
@@ -0,0 +1,40 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/perfect-panel/server/internal/svc"
|
||||
"github.com/perfect-panel/server/internal/types"
|
||||
"github.com/perfect-panel/server/pkg/logger"
|
||||
)
|
||||
|
||||
type GetAppVersionLogic struct {
|
||||
logger.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
// NewGetAppVersionLogic 获取 App 版本信息
|
||||
func NewGetAppVersionLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetAppVersionLogic {
|
||||
return &GetAppVersionLogic{
|
||||
Logger: logger.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
// GetAppVersion 根据平台返回最新版本信息
|
||||
func (l *GetAppVersionLogic) GetAppVersion(req *types.GetAppVersionRequest) (resp *types.ApplicationVersion, err error) {
|
||||
// TODO: 后续对接数据库实现
|
||||
resp = &types.ApplicationVersion{
|
||||
Version: "1.0.0",
|
||||
MinVersion: "1.0.0",
|
||||
ForceUpdate: false,
|
||||
Description: map[string]string{
|
||||
"zh-CN": "初始版本",
|
||||
"en-US": "Initial version",
|
||||
},
|
||||
IsDefault: true,
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/perfect-panel/server/internal/svc"
|
||||
"github.com/perfect-panel/server/internal/types"
|
||||
"github.com/perfect-panel/server/pkg/logger"
|
||||
)
|
||||
|
||||
type GetDownloadLinkLogic struct {
|
||||
logger.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
// NewGetDownloadLinkLogic 获取下载链接
|
||||
func NewGetDownloadLinkLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetDownloadLinkLogic {
|
||||
return &GetDownloadLinkLogic{
|
||||
Logger: logger.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
// GetDownloadLink 根据邀请码和平台动态生成下载链接
|
||||
// 生成的链接格式: https://{host}/v1/common/client/download/file/{platform}-{version}-ic_{invite_code}.{ext}
|
||||
// Nginx 会拦截此请求,将其映射到实际文件,并在 Content-Disposition 中设置带邀请码的文件名
|
||||
func (l *GetDownloadLinkLogic) GetDownloadLink(req *types.GetDownloadLinkRequest) (resp *types.GetDownloadLinkResponse, err error) {
|
||||
// 1. 获取站点域名 (数据库配置通常会覆盖文件配置)
|
||||
host := l.svcCtx.Config.Site.Host
|
||||
if host == "" {
|
||||
// 保底域名
|
||||
host = "tapi.airoport.co"
|
||||
}
|
||||
|
||||
// 2. 版本号 (后续可以从数据库或配置中读取)
|
||||
version := "1.0.0"
|
||||
|
||||
// 3. 根据平台确定文件扩展名
|
||||
var ext string
|
||||
switch req.Platform {
|
||||
case "windows":
|
||||
ext = ".exe"
|
||||
case "mac":
|
||||
ext = ".dmg"
|
||||
case "android":
|
||||
ext = ".apk"
|
||||
case "ios":
|
||||
ext = ".ipa"
|
||||
default:
|
||||
ext = ".bin"
|
||||
}
|
||||
|
||||
// 4. 构建文件名: 平台-版本号-ic_邀请码.扩展名
|
||||
filename := fmt.Sprintf("%s-%s-ic_%s%s", req.Platform, version, req.InviteCode, ext)
|
||||
|
||||
// 5. 构建完整 URL (Nginx 会拦截此路径进行虚拟更名处理)
|
||||
url := fmt.Sprintf("https://%s/v1/common/client/download/file/%s", host, filename)
|
||||
|
||||
return &types.GetDownloadLinkResponse{
|
||||
Url: url,
|
||||
}, nil
|
||||
}
|
||||
@@ -95,14 +95,22 @@ func (l *SendEmailCodeLogic) SendEmailCode(req *types.SendCodeRequest) (resp *ty
|
||||
expireTime = 900
|
||||
}
|
||||
fmt.Printf("expireTime: %v\n", expireTime)
|
||||
expireMinutes := expireTime / 60
|
||||
taskPayload.Content = map[string]interface{}{
|
||||
"Type": req.Type,
|
||||
"SiteLogo": l.svcCtx.Config.Site.SiteLogo,
|
||||
"SiteName": l.svcCtx.Config.Site.SiteName,
|
||||
"Expire": expireTime / 60,
|
||||
"Expire": expireMinutes,
|
||||
"Code": code,
|
||||
}
|
||||
|
||||
// Override for account deletion
|
||||
if constant.ParseVerifyType(req.Type) == constant.DeleteAccount {
|
||||
taskPayload.Subject = "注销账号验证"
|
||||
taskPayload.Content["Content"] = fmt.Sprintf("您正在申请注销账号,验证码为:%s,有效期 %d 分钟。如非本人操作,请忽略。", code, expireMinutes)
|
||||
}
|
||||
// Save to Redis
|
||||
|
||||
payload = CacheKeyPayload{
|
||||
Code: code,
|
||||
LastAt: time.Now().Unix(),
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/perfect-panel/server/internal/config"
|
||||
"github.com/perfect-panel/server/internal/svc"
|
||||
"github.com/perfect-panel/server/pkg/constant"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestSendEmailCodeLogic_DeleteAccountContent(t *testing.T) {
|
||||
// 这是一个模拟测试,主要展示逻辑判断是否正确
|
||||
// 实际运行需要 Mock Redis 和 asynq
|
||||
_ = &SendEmailCodeLogic{
|
||||
svcCtx: &svc.ServiceContext{
|
||||
Config: config.Config{
|
||||
VerifyCode: config.VerifyCode{ExpireTime: 900},
|
||||
Site: config.SiteConfig{
|
||||
SiteLogo: "logo.png",
|
||||
SiteName: "PPanel",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
code := "123456"
|
||||
expireMinutes := 15
|
||||
|
||||
// 模拟逻辑中的覆盖逻辑
|
||||
// 注意:这里我们不能直接测试 SendEmailCode 函数(因为它依赖 Redis/Asynq),
|
||||
// 但我们可以验证我们写的覆盖逻辑片段是否符合预期。
|
||||
|
||||
taskPayloadSubject := "Verification code"
|
||||
taskPayloadContent := map[string]interface{}{
|
||||
"Type": uint8(4),
|
||||
"SiteLogo": "logo.png",
|
||||
"SiteName": "PPanel",
|
||||
"Expire": expireMinutes,
|
||||
"Code": code,
|
||||
}
|
||||
|
||||
// 触发我们的逻辑
|
||||
if constant.ParseVerifyType(uint8(4)) == constant.DeleteAccount {
|
||||
taskPayloadSubject = "注销账号验证"
|
||||
taskPayloadContent["Content"] = fmt.Sprintf("您正在申请注销账号,验证码为:%s,有效期 %d 分钟。如非本人操作,请忽略。", code, expireMinutes)
|
||||
}
|
||||
|
||||
assert.Equal(t, "注销账号验证", taskPayloadSubject)
|
||||
assert.Contains(t, taskPayloadContent["Content"].(string), "注销账号")
|
||||
assert.Contains(t, taskPayloadContent["Content"].(string), code)
|
||||
}
|
||||
Reference in New Issue
Block a user