Files
ycc-proxy-server/app/main/api/internal/logic/agent/getinvitelinklogic.go

157 lines
5.2 KiB
Go
Raw Normal View History

2025-11-27 13:09:54 +08:00
package agent
import (
"context"
"database/sql"
"fmt"
2025-12-02 19:57:10 +08:00
"time"
2025-11-27 13:09:54 +08:00
"ycc-server/app/main/model"
"ycc-server/common/ctxdata"
2025-12-02 19:57:10 +08:00
"ycc-server/common/globalkey"
2025-11-27 13:09:54 +08:00
"ycc-server/common/tool"
"ycc-server/common/xerr"
"github.com/pkg/errors"
"ycc-server/app/main/api/internal/svc"
"ycc-server/app/main/api/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type GetInviteLinkLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewGetInviteLinkLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetInviteLinkLogic {
return &GetInviteLinkLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
2025-12-02 19:57:10 +08:00
func (l *GetInviteLinkLogic) GetInviteLink(req *types.GetInviteLinkReq) (resp *types.GetInviteLinkResp, err error) {
2025-11-27 13:09:54 +08:00
// 1. 获取当前代理信息
userID, err := ctxdata.GetUidFromCtx(l.ctx)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取用户信息失败, %v", err)
}
agent, err := l.svcCtx.AgentModel.FindOneByUserId(l.ctx, userID)
if err != nil {
if errors.Is(err, model.ErrNotFound) {
return nil, errors.Wrapf(xerr.NewErrMsg("您不是代理"), "")
}
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询代理信息失败, %v", err)
}
2025-12-02 19:57:10 +08:00
// 2. 验证邀请码参数
if req.InviteCode == "" {
return nil, errors.Wrapf(xerr.NewErrMsg("邀请码不能为空"), "")
}
2025-11-27 13:09:54 +08:00
2025-12-02 19:57:10 +08:00
// 3. 查询邀请码是否存在且属于当前代理
inviteCodeRecord, err := l.svcCtx.AgentInviteCodeModel.FindOneByCode(l.ctx, req.InviteCode)
if err != nil {
if errors.Is(err, model.ErrNotFound) {
return nil, errors.Wrapf(xerr.NewErrMsg("邀请码不存在"), "")
2025-11-27 13:09:54 +08:00
}
2025-12-02 19:57:10 +08:00
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询邀请码失败, %v", err)
}
2025-11-27 13:09:54 +08:00
2025-12-02 19:57:10 +08:00
// 4. 验证邀请码是否属于当前代理
if !inviteCodeRecord.AgentId.Valid || inviteCodeRecord.AgentId.Int64 != agent.Id {
return nil, errors.Wrapf(xerr.NewErrMsg("无权使用此邀请码"), "")
}
2025-11-27 13:09:54 +08:00
2025-12-02 19:57:10 +08:00
// 5. 验证邀请码状态
if inviteCodeRecord.Status != 0 {
if inviteCodeRecord.Status == 1 {
return nil, errors.Wrapf(xerr.NewErrMsg("邀请码已使用"), "")
}
return nil, errors.Wrapf(xerr.NewErrMsg("邀请码已失效"), "")
}
2025-11-27 13:09:54 +08:00
2025-12-02 19:57:10 +08:00
// 6. 验证邀请码是否过期
if inviteCodeRecord.ExpireTime.Valid && inviteCodeRecord.ExpireTime.Time.Before(time.Now()) {
return nil, errors.Wrapf(xerr.NewErrMsg("邀请码已过期"), "")
2025-11-27 13:09:54 +08:00
}
2025-12-02 19:57:10 +08:00
// 7. 使用默认target_path如果未提供
targetPath := req.TargetPath
if targetPath == "" {
targetPath = fmt.Sprintf("/register?invite_code=%s", req.InviteCode)
2025-11-27 13:09:54 +08:00
}
2025-12-02 19:57:10 +08:00
// 8. 生成短链类型2=邀请好友)
shortLink, err := l.createInviteShortLink(inviteCodeRecord.Id, req.InviteCode, targetPath)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "生成短链失败, %v", err)
}
2025-11-27 13:09:54 +08:00
return &types.GetInviteLinkResp{
2025-12-02 19:57:10 +08:00
InviteLink: shortLink,
2025-11-27 13:09:54 +08:00
}, nil
}
2025-12-02 19:57:10 +08:00
// createInviteShortLink 创建邀请好友短链
func (l *GetInviteLinkLogic) createInviteShortLink(inviteCodeId int64, inviteCode, targetPath string) (string, error) {
promotionConfig := l.svcCtx.Config.Promotion
// 如果没有配置推广域名,返回空字符串(保持向后兼容)
if promotionConfig.PromotionDomain == "" {
l.Errorf("推广域名未配置,返回空链接")
return "", nil
}
// 先查询是否已存在短链
existingShortLink, err := l.svcCtx.AgentShortLinkModel.FindOneByInviteCodeIdTypeDelState(l.ctx, sql.NullInt64{Int64: inviteCodeId, Valid: true}, 2, globalkey.DelStateNo)
if err == nil && existingShortLink != nil {
// 已存在短链,直接返回
return fmt.Sprintf("%s/s/%s", promotionConfig.PromotionDomain, existingShortLink.ShortCode), nil
}
if err != nil && !errors.Is(err, model.ErrNotFound) {
return "", errors.Wrapf(err, "查询短链失败")
}
// 生成短链标识6位随机字符串大小写字母+数字)
var shortCode string
maxRetries := 10 // 最大重试次数
for retry := 0; retry < maxRetries; retry++ {
shortCode = tool.Krand(6, tool.KC_RAND_KIND_ALL)
// 检查短链标识是否已存在
_, err := l.svcCtx.AgentShortLinkModel.FindOneByShortCodeDelState(l.ctx, shortCode, globalkey.DelStateNo)
if err != nil {
if errors.Is(err, model.ErrNotFound) {
// 短链标识不存在,可以使用
break
}
return "", errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "检查短链标识失败, %v", err)
}
// 短链标识已存在,继续生成
if retry == maxRetries-1 {
return "", errors.Wrapf(xerr.NewErrMsg("生成短链失败,请重试"), "")
}
}
// 创建短链记录类型2=邀请好友)
shortLink := &model.AgentShortLink{
Type: 2, // 邀请好友
InviteCodeId: sql.NullInt64{Int64: inviteCodeId, Valid: inviteCodeId > 0},
InviteCode: sql.NullString{String: inviteCode, Valid: inviteCode != ""},
ShortCode: shortCode,
TargetPath: targetPath,
PromotionDomain: promotionConfig.PromotionDomain,
}
_, err = l.svcCtx.AgentShortLinkModel.Insert(l.ctx, nil, shortLink)
if err != nil {
return "", errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "保存短链失败, %v", err)
}
return fmt.Sprintf("%s/s/%s", promotionConfig.PromotionDomain, shortCode), nil
}