package agentSer import ( "bytes" "context" "errors" "fmt" "stat/api/proto" "stat/common/log" "stat/common/stdLog" "stat/common/utils" "stat/middleware/define" "stat/models/channelmod" "stat/statg" "strconv" "strings" "time" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo/options" ) func GetChannelInfoWithLockStatus(ctx context.Context, channel string) (*channelmod.ChannelInfo, stdLog.CodeType, error) { channelFilter := bson.M{channelmod.FN.ChannelInfo.Channel: channel} channelInfo, err := channelmod.FindOneChannelInfo(ctx, channelFilter) if err != nil || channelInfo.Channel == "" { return nil, stdLog.AgentAccountNotExists, fmt.Errorf("代理账号 %s 不存在", channel) } if channelInfo.Type.IsChild() { channelMap, _, err := MakeChannelAndRuleMap(ctx, channelInfo) if err != nil { return nil, stdLog.QueryDataError, err } lock, status, showDivide := channelMap.GetLockStatusAndShowDivide(channelInfo) channelInfo.Lock = lock channelInfo.Status = status channelInfo.ChildShowDivideRate = showDivide } return channelInfo, stdLog.Success, nil } func CheckToken(ctx context.Context, channel string, token string) error { channelFilter := bson.M{channelmod.FN.ChannelInfo.Channel: channel} channelInfo, err := channelmod.FindOneChannelInfo(ctx, channelFilter) if err != nil { return err } if channelInfo.Channel == "" { return fmt.Errorf("代理账号 %s 不存在", channel) } if channelInfo.Lock || !channelInfo.Status { return fmt.Errorf("代理账号 %s 被禁止", channel) } if channelInfo.Token != token { return fmt.Errorf("登陆信息已过期,请重新登陆") } if time.Since(channelInfo.CheckTokenTime) > 6*time.Hour { doc := bson.M{"$set": bson.M{ channelmod.FN.ChannelInfo.CheckTokenTime: time.Now(), }} if err = channelmod.UpdateOneChannelInfo(ctx, bson.M{channelmod.FN.ChannelInfo.Channel: channelInfo.Channel}, doc); err != nil { return err } channelInfoWithLock, _, err := GetChannelInfoWithLockStatus(ctx, channel) if err != nil { return err } if channelInfoWithLock.Lock || !channelInfoWithLock.Status { doc := bson.M{"$set": bson.M{ channelmod.FN.ChannelInfo.Token: "", // 清空token }} if err = channelmod.UpdateOneChannelInfo(ctx, bson.M{channelmod.FN.ChannelInfo.Channel: channelInfo.Channel}, doc); err != nil { return err } return fmt.Errorf("本账号的上级代理账号 %s 被禁止", channel) } } return nil } // 代理商账号登陆 func AgentLogin(ctx context.Context, ip string, param proto.AgentLoginReq) (code stdLog.CodeType, channelInfo *channelmod.ChannelInfo) { var err error channelInfo, code, err = GetChannelInfoWithLockStatus(ctx, *param.Account) if err != nil { return } // 禁止登陆 if channelInfo.Lock || !channelInfo.Status { code = stdLog.AgentHasLocked return } if *param.Password != channelInfo.Password { code = stdLog.AdminPasswordError return } if len(param.ImgCode) != 4 { code = stdLog.VerifySmsCodeFailed return } imgs := make([]byte, 4) for i := range param.ImgCode { pi, err := strconv.Atoi(string(param.ImgCode[i])) if err != nil { code = stdLog.VerifySmsCodeFailed return } imgs[i] = byte(pi) } imgCodeByte := statg.VerifyIMGStore.Get(param.ImgID, true) if bytes.Equal(imgCodeByte, imgs) { channelInfo.ShowMagic = 1 } else { code = stdLog.VerifySmsCodeFailed return } // 生成token claims := define.Claims{ Type: define.Channel, Name: *param.Account, ShowMagic: strconv.Itoa(int(channelInfo.ShowMagic)), } //fmt.Println("claims", claims) if channelInfo.ShowMagic >= 3 { statg.Bot.SendMonitorMessage("渠道" + channelInfo.Channel + "风险登陆多次已禁止登陆.") } newToken, err := define.GenToken(&claims) if err != nil { log.Error("GenerateUserToken failed", log.E(err)) code = stdLog.Failure return code, channelInfo } channelInfo.Token = newToken // 刷新token doc := bson.M{"$set": bson.M{ channelmod.FN.ChannelInfo.Token: newToken, channelmod.FN.ChannelInfo.ShowMagic: channelInfo.ShowMagic, channelmod.FN.ChannelInfo.IP: ip, }} if err = channelmod.UpdateOneChannelInfo(ctx, bson.M{channelmod.FN.ChannelInfo.Channel: channelInfo.Channel}, doc); err != nil { code = stdLog.Failure return code, channelInfo } code = stdLog.Success return } func AgentChannelAppInfo(ctx context.Context, req proto.ChannelAppInfoReq) (*proto.ChannelAppInfoResp, error) { checkFilter := bson.M{ channelmod.FN.ChannelInfo.Channel: req.Channel, } channelInfo, err := channelmod.FindOneChannelInfo(ctx, checkFilter) if err != nil { return nil, err } if channelInfo.Channel != req.Channel { return nil, fmt.Errorf("channel not found. %s", req.Channel) } filter := bson.M{} if channelInfo.Type == channelmod.ChannelTypeParent { filter[channelmod.FN.ChannelInfo.Channel] = channelInfo.Channel } else { filter[channelmod.FN.ChannelInfo.Channel] = channelInfo.ParentChannel } ruleList, err := channelmod.FindManyChannelDeductionRule(ctx, filter) if err != nil { log.Error("AgentChannelAppInfo FindManyChannelDeductionRule", log.Any("channel", req.Channel), log.E(err)) return nil, err } resp := &proto.ChannelAppInfoResp{ List: make([]proto.ChannelAppInfo, 0), } for _, ruleInfo := range ruleList { temp := proto.ChannelAppInfo{ AppId: ruleInfo.AppId, AppName: ruleInfo.AppName, LandingPage: ruleInfo.LandingPage + fmt.Sprintf("?dc=%s", req.Channel), } resp.List = append(resp.List, temp) } return resp, nil } // AgentChannelListInfo 查询渠道列表 func AgentChannelListInfo(ctx context.Context, channel string, req *proto.AgentChannelInfoSearch) ( *proto.AgentChannelInfoSearchResp, error) { filter := bson.M{"$or": bson.A{ bson.M{channelmod.FN.ChannelInfo.Channel: channel}, bson.M{channelmod.FN.ChannelInfo.ParentAgent: channel}, }} opt := &options.FindOptions{} opt.SetSort(bson.M{channelmod.FN.ChannelInfo.CreatedAt: -1}) opt.SetSkip((req.PageNum - 1) * req.PageSize) opt.SetLimit(req.PageSize) resp := &proto.AgentChannelInfoSearchResp{} if req.AppId != nil { filter[channelmod.FN.ChannelInfo.AppIds] = bson.M{"$in": []int32{*req.AppId}} } if req.Type != nil { filter[channelmod.FN.ChannelInfo.Type] = *req.Type } total, serr := channelmod.CountChannelInfos(ctx, filter) if serr != nil { return nil, serr } if total == 0 { return resp, nil } channelInfoList, err := channelmod.FindManyChannelInfo(ctx, filter, opt) if err != nil { return nil, err } resp.List = make([]proto.ChannelAgentInfo, 0) for _, channchannelInfo := range channelInfoList { tmp := proto.ChannelAgentInfo{ Channel: channchannelInfo.Channel, AppIds: channchannelInfo.AppIds, UserName: channchannelInfo.UserName, ParentAgent: channchannelInfo.ParentAgent, ChildCount: channchannelInfo.ChildCount, Status: channchannelInfo.Status, Mobile: channchannelInfo.Mobile, Type: channchannelInfo.Type, Remark: channchannelInfo.Remark, Lock: channchannelInfo.Lock, Wallet: channchannelInfo.Wallet, CreatedAt: channchannelInfo.CreatedAt, UpdatedAt: channchannelInfo.UpdatedAt, } ruleFilter := bson.M{ channelmod.FN.ChannelDeductionRule.Channel: channchannelInfo.Channel, } ruleInfoList, _ := channelmod.FindManyChannelDeductionRule(ctx, ruleFilter) for _, ruleInfo := range ruleInfoList { tmp.Settlement = ruleInfo.Settlement tmp.CPAPrice = ruleInfo.CPAPrice tmp.CPSRate = ruleInfo.CPSRate tmp.DivideRate = ruleInfo.DivideRate tmp.AppType = ruleInfo.AppType tmp.PromoteMode = ruleInfo.PromoteMode tmp.AppIds = []int32{int32(ruleInfo.AppId)} if tmp.DivideRate == 0 { tmp.DivideRate = 100 } if tmp.Channel == channel { tmp.DivideRate = 100 } resp.List = append(resp.List, tmp) } } resp.Total = total return resp, nil } // AgentChannelRuleUpdate 更新渠道信息 func AgentChannelRuleUpdate(ctx context.Context, channel string, req *proto.AgentChannelRuleUpdate) error { // 查找要修改规则的子代理 channelFilter := bson.M{ channelmod.FN.ChannelInfo.Channel: req.Channel, channelmod.FN.ChannelInfo.ParentAgent: channel, } channelInfo, err := channelmod.FindOneChannelInfo(ctx, channelFilter) if err != nil { return err } if channelInfo.Channel != req.Channel { return fmt.Errorf("channel not found %s", req.Channel) } if req.CPSRate == nil && req.CPAPrice == nil && req.DivideRate == nil && req.ChildShowDivideRate == nil { return nil } if req.CPSRate != nil && !InRangeInt64(*req.CPSRate, 0, 100) { return fmt.Errorf("CPS比例 (%d) 必须在 0-100 之间", *req.CPSRate) } if req.DivideRate != nil && !InRangeInt64(*req.DivideRate, 0, 100) { return fmt.Errorf("分成比例 (%d) 必须在 0-100 之间", *req.CPSRate) } // 规则检查 parentRules, err := channelmod.FindManyChannelDeductionRule(ctx, bson.M{channelmod.FN.ChannelDeductionRule.Channel: channelInfo.ParentAgent}) if err != nil { return err } if req.CPAPrice != nil { parentCPA := int64(0) for _, rule := range parentRules { if rule.CPAPrice > 0 { if parentCPA <= 0 { parentCPA = rule.CPAPrice } else { if rule.CPAPrice < parentCPA { parentCPA = rule.CPAPrice } } } } if *req.CPAPrice > parentCPA || *req.CPAPrice < 0 { return fmt.Errorf("下级CPA价格 (%d) 必须在范围 0-%d 之间,不能大于你自己的CPA价格", *req.CPAPrice/100, parentCPA/100) } } if req.CPSRate != nil { parentCPSRate := int64(0) for _, rule := range parentRules { if rule.CPSRate > 0 { if parentCPSRate <= 0 { parentCPSRate = rule.CPSRate } else { if rule.CPSRate < parentCPSRate { parentCPSRate = rule.CPSRate } } } } if *req.CPSRate > parentCPSRate || *req.CPSRate < 0 { return fmt.Errorf("下级CPS比例 (%d) 必须在范围 0-%d 之间, 不能大于你自己的CPS比例", *req.CPSRate, parentCPSRate) } } // 更新规则 setdoc := bson.M{} if req.CPAPrice != nil { setdoc[channelmod.FN.ChannelDeductionRule.CPAPrice] = *req.CPAPrice } if req.CPSRate != nil { setdoc[channelmod.FN.ChannelDeductionRule.CPSRate] = *req.CPSRate } if req.DivideRate != nil { setdoc[channelmod.FN.ChannelDeductionRule.DivideRate] = *req.DivideRate } if err := channelmod.UpdateManyChannelDeductionRule(ctx, bson.M{channelmod.FN.ChannelDeductionRule.Channel: req.Channel}, bson.M{"$set": setdoc}, ); err != nil { return err } // 更新子代理是否显示分成比例 if req.ChildShowDivideRate != nil || req.Remark != nil { doc := bson.M{} if req.ChildShowDivideRate != nil { doc[channelmod.FN.ChannelInfo.ChildShowDivideRate] = *req.ChildShowDivideRate } if req.Remark != nil { doc[channelmod.FN.ChannelInfo.Remark] = *req.Remark } if err = channelmod.UpdateOneChannelInfo(ctx, channelFilter, bson.M{"$set": doc}); err != nil { return err } } return nil } // AgentChannelInfoUpdate 更新渠道信息 func AgentChannelInfoUpdate(ctx context.Context, channel string, req *proto.AgentChannelInfoUpdate) error { checkFilter := bson.M{ channelmod.FN.ChannelInfo.Channel: req.Channel, } channelInfo, err := channelmod.FindOneChannelInfo(ctx, checkFilter) if err != nil { return err } if channelInfo.Channel != req.Channel { return fmt.Errorf("channel not found. %s", req.Channel) } if req.WalletAddr1 != nil || req.WalletAddr2 != nil { if channelInfo.Channel == channel { return fmt.Errorf("您不可以修改自己的钱包地址,请联系您的上级代理协助修改") } } if !(channelInfo.Channel == channel || channelInfo.ParentAgent == channel) { return fmt.Errorf("channel not found! %s", req.Channel) } setdoc := bson.M{ channelmod.FN.ChannelInfo.UpdatedAt: time.Now(), } if req.Status != nil { setdoc[channelmod.FN.ChannelInfo.Status] = *req.Status } if req.Mobile != nil { setdoc[channelmod.FN.ChannelInfo.Mobile] = *req.Mobile } if req.WalletAddr1 != nil { setdoc[channelmod.FN.ChannelInfo.Wallet.Addr1] = *req.WalletAddr1 } if req.WalletAddr2 != nil { setdoc[channelmod.FN.ChannelInfo.Wallet.Addr2] = *req.WalletAddr2 } return channelmod.UpdateOneChannelInfo(ctx, bson.M{channelmod.FN.ChannelInfo.Channel: req.Channel}, bson.M{"$set": setdoc}, ) } // AgentChannelPasswordReset 子渠道密码重置 func AgentChannelPasswordReset(ctx context.Context, channel string, req *proto.AgentChannelPasswordReset) error { checkFilter := bson.M{ channelmod.FN.ChannelInfo.Channel: req.Channel, } channelInfo, err := channelmod.FindOneChannelInfo(ctx, checkFilter) if err != nil { return err } if channelInfo.Channel != req.Channel { return fmt.Errorf("代理没找到. %s", req.Channel) } if channelInfo.ParentAgent != channel { return errors.New("只能重置直接下级代理的密码! ") } if req.Password == "" { return errors.New("新密码不能为空! ") } setdoc := bson.M{ channelmod.FN.ChannelInfo.UpdatedAt: time.Now(), channelmod.FN.ChannelInfo.Password: req.Password, } return channelmod.UpdateOneChannelInfo(ctx, bson.M{channelmod.FN.ChannelInfo.Channel: req.Channel}, bson.M{"$set": setdoc}, ) } // AgentChannelPasswordUpdate 更新渠道密码 func AgentChannelPasswordUpdate(ctx context.Context, channel string, req *proto.AgentChannelPasswordUpdate) error { checkFilter := bson.M{ channelmod.FN.ChannelInfo.Channel: channel, } channelInfo, err := channelmod.FindOneChannelInfo(ctx, checkFilter) if err != nil { return err } if channelInfo.Channel != channel { return fmt.Errorf("channel not found. %s", channel) } if channelInfo.Password != req.OldPassword { return errors.New("旧密码输入错误") } if req.NewPassword == "" { return errors.New("新密码不能为空! ") } setdoc := bson.M{ channelmod.FN.ChannelInfo.UpdatedAt: time.Now(), channelmod.FN.ChannelInfo.Password: req.NewPassword, } return channelmod.UpdateOneChannelInfo(ctx, bson.M{channelmod.FN.ChannelInfo.Channel: channel}, bson.M{"$set": setdoc}, ) } func GetChildNewChannelNameAndRootChannelName(ctx context.Context, channelParent *channelmod.ChannelInfo) (string, string, error) { maxid := 0 filter := bson.M{} if channelParent.Type == channelmod.ChannelTypeParent { filter[channelmod.FN.ChannelInfo.ParentChannel] = channelParent.Channel } else { filter[channelmod.FN.ChannelInfo.ParentAgent] = channelParent.Channel } channlList, err := channelmod.FindManyChannelInfo(ctx, filter) if err != nil { log.Error("AddAgentChannelInfo CountChannelInfos", log.Any("channel", channelParent.Channel), log.E(err)) return "", "", err } for _, v := range channlList { id, err := strconv.Atoi(string(strings.Replace(v.Channel, channelParent.Channel, "", -1))) if err == nil && id > maxid { maxid = id } } maxid = maxid + 1 childChannelName := channelParent.Channel + fmt.Sprintf("%.2d", maxid) rootChannelName := "" if channelParent.Type == channelmod.ChannelTypeParent { // 一级代理 rootChannelName = channelParent.Channel } else { if channelParent.ParentChannel == "" { // 如果子级代理的父代理为空 //rootChannelName = channelParent.Channel return "", "", fmt.Errorf("子级代理【%s】的顶级代理空时不能添加子代理!", channelParent.Channel) } else { rootChannelName = channelParent.ParentChannel } } return childChannelName, rootChannelName, nil } // AddAgentChannelInfo 渠道添加一个子渠道 func AddAgentChannelInfo(ctx context.Context, channel string, req *proto.AgentChannelInfoAdd) error { channelInfo, _, err := GetChannelInfoWithLockStatus(ctx, channel) if err != nil { return err } if channelInfo.Lock || !channelInfo.Status { return fmt.Errorf("您的代理或上级代理已被禁止") } childChannelName, rootChannelName, err := GetChildNewChannelNameAndRootChannelName(ctx, channelInfo) if err != nil { return err } childChannelType := channelInfo.Type.Child() if childChannelType.IsNone() { return errors.New("您的代理等级无法添加子渠道") } now := time.Now() newChannelInfo := channelmod.ChannelInfo{ Channel: childChannelName, UserName: channelInfo.UserName, AppIds: channelInfo.AppIds, ParentChannel: rootChannelName, ParentAgent: channel, Password: req.Password, Status: true, Mobile: req.Mobile, Type: childChannelType, Remark: req.Remark, Wallet: channelmod.Wallet{ Addr1: req.WalletAddr1, Addr2: req.WalletAddr2, }, Lock: false, ShowMagic: 0, CreatedAt: now, UpdatedAt: now, } err = channelmod.InsertOneChannelInfo(ctx, &newChannelInfo) if err != nil { log.Error("AddChannelInfo InsertOneChannelInfo", log.Any("channel", newChannelInfo.ParentChannel), log.E(err)) return err } // 增加子渠道数量 setdoc := bson.M{"$inc": bson.M{channelmod.FN.ChannelInfo.ChildCount: 1}} err = channelmod.UpdateOneChannelInfo(ctx, bson.M{channelmod.FN.ChannelInfo.Channel: channel}, setdoc) if err != nil { log.Error("AddChannelInfo InsertOneChannelInfo", log.Any("channel", newChannelInfo.ParentChannel), log.E(err)) return err } for _, appid := range channelInfo.AppIds { checkFilter := bson.M{channelmod.FN.ChannelDeductionRule.Channel: channel, channelmod.FN.ChannelDeductionRule.AppId: appid} ChannelDeductionRule, err := channelmod.FindOneChannelDeductionRule(ctx, checkFilter) if err != nil || ChannelDeductionRule.Channel != channel { log.Error("AddAgentChannelInfo FindOneChannelDeductionRule", log.Any("channel", channel), log.Any("appid", appid), log.E(err)) continue } newChannelRule := &channelmod.ChannelDeductionRule{ Channel: newChannelInfo.Channel, AppId: ChannelDeductionRule.AppId, AppName: ChannelDeductionRule.AppName, AppType: ChannelDeductionRule.AppType, PromoteMode: ChannelDeductionRule.PromoteMode, Settlement: ChannelDeductionRule.Settlement, First: ChannelDeductionRule.First, Second: ChannelDeductionRule.Second, Third: ChannelDeductionRule.Third, Fourth: ChannelDeductionRule.Fourth, Fifth: ChannelDeductionRule.Fifth, CPAPrice: ChannelDeductionRule.CPAPrice, CPSRate: ChannelDeductionRule.CPSRate, CPSBegin: ChannelDeductionRule.CPSBegin, CPSDeductionRate: ChannelDeductionRule.CPSDeductionRate, BeginTime: ChannelDeductionRule.BeginTime, SettlementTime: now, TodayTime: utils.BeginOfToday(), TodayDeduction: 0, CreatedAt: now, UpdatedAt: now, } err = channelmod.InsertOneChannelDeductionRule(ctx, newChannelRule) if err != nil { log.Error("AddAgentChannelInfo InsertOneChannelDeductionRule", log.Any("channel", channel), log.Any("appid", appid), log.E(err)) continue } } return nil } // GetAgentSummaryStatChild 查询渠道扣量规则信息 func GetAgentSummaryStatChild(ctx context.Context, channel string, req *proto.AgentSummaryStatChildSearch) (*proto.AgentSummaryStatChildResp, error) { resp := &proto.AgentSummaryStatChildResp{ List: make(proto.AgentSummaryStatChildList, 0), } summary, err := GetAgentSummary(ctx, channel, nil, nil, nil, nil) if err != nil { return nil, err } total, list := summary.GetAgentSummaryStats(OutputStatListTypeChild, req.PageNum, req.PageSize) resp.Total = total for _, item := range list { resp.List = append(resp.List, item.ToAgentSummaryStatChild()) } return resp, nil } // GetAgentSummaryStatHome 查询渠道扣量规则信息 func GetAgentSummaryStatHome(ctx context.Context, channel string, req *proto.AgentSummaryStatHomeSearch) (*proto.AgentSummaryStatHomeResp, error) { resp := &proto.AgentSummaryStatHomeResp{ List: make(proto.AgentSummaryStatHomeList, 0), } summary, err := GetAgentSummary(ctx, channel, nil, nil, nil, nil) if err != nil { return nil, err } total, list := summary.GetAgentSummaryStats(OutputStatListTypeSelf, req.PageNum, req.PageSize) resp.Total = total resp.List = list return resp, nil } // GetAgentChannelStat 查询渠道扣量规则信息 func GetAgentChannelStat(ctx context.Context, channel string, req *proto.AgentChannelStatSearch) (*proto.AgentChannelStatResp, error) { resp := &proto.AgentChannelStatResp{ List: make([]*proto.AgentDeductedStat, 0), } summary, err := GetAgentSummary(ctx, channel, req.Channel, req.AppId, req.Start, req.End) if err != nil { return nil, err } total, list := summary.GetAgentStats(OutputStatListTypeAll, req.PageNum, req.PageSize) resp.Total = total resp.List = list resp.TotalInfo = *summary.StatTotal return resp, nil }