package campaignuser import ( "joybuywork/internal/app" "joybuywork/internal/consts" "joybuywork/internal/consts/ckey" "joybuywork/internal/plugins/jsonm" "joybuywork/internal/repository/cache" "joybuywork/internal/repository/dbcheck" "joybuywork/internal/repository/finder" "joybuywork/internal/repository/model" "joybuywork/internal/repository/mtype" "joybuywork/internal/service/cmm" "joybuywork/internal/service/provider" "joybuywork/internal/service/provider/fissionaction" "joybuywork/internal/service/provider/pusher" "joybuywork/internal/utils" "joybuywork/internal/utils/blink" "joybuywork/internal/utils/lockdo" "joybuywork/internal/utils/logic" pb "joybuywork/proto/go_proto/w_campaign_user" "joybuywork/proto/go_proto/workerr" "strings" "time" c_fuserpb "gits.branchcn.com/backend/certified/proto/go_proto/c_fuser" ddevicepb "gits.branchcn.com/backend/deeplink/proto/go_proto/ddevice" linkpb "gits.branchcn.com/backend/shortlink/proto/go_proto/link" ) type Visit struct { logic.Logic Req *pb.VisitReq Res *pb.VisitRes clearUser bool // 是否已经清楚的用户缓存 changeLangMark, changeLvMark bool //一些数据是否有被更改 cpnControl *provider.CampaignTZ wbu *model.FissionWebUser device *ddevicepb.FindBlackboxRes } func (s *Visit) Run() error { return logic.Run(s) } func (s *Visit) Exec() (err error) { cpn, channel, err := s.campaign() if err != nil { return } user, err := s.user(cpn, channel) if err != nil { return } err = s.setLink(cpn, channel, user) if err != nil { return } err = s.token(cpn, user) if err != nil { return } return s.track(cpn, user) } func (s *Visit) campaign() (cpn *model.FissionCampaign, channel *model.FissionCampaignChannel, err error) { cpn, err = finder.Campaign(s.Ctx, s.Req.GetHid()) if err != nil { err = s.BE().CacheError(err) return } if cpn == nil || cpn.IsDel == mtype.Yes { err = workerr.NotFound("not found cpn") return } err = s._cert(cpn.ProjectID) if err != nil { return } // 用户要绑定的渠道 channel, err = cmm.NewCMM(s.Ctx, s.GetDao()).UserBindChannel(cpn.ID, s.Req.GetCid()) if err != nil { return } if s.Req.GetLang() == "" { s.Req.Lang = cpn.GetLangMarks()[0] } if s.Req.GetWid() != "" { s.wbu, err = cache.NewFissionWebUser(s.Ctx).FindByWebId(cpn.ID, s.Req.GetWid()) if err != nil { err = s.BE().CacheError(err) return } } s.cpnControl = provider.NewCampaignTZ(s.Ctx, cpn, s.Req.Lang) err = s._hasParent(cpn) if err != nil { return } return } func (s *Visit) user(cpn *model.FissionCampaign, channel *model.FissionCampaignChannel) (user *model.FissionUser, err error) { defer func() { if err == nil && user != nil && user.IsView != mtype.Yes { s.Res.HasParent = user.ParentID > 0 } if err == nil && user != nil && s.wbu == nil { s.wbu, err = cache.NewFissionWebUser(s.Ctx).FindByUserId(cpn.ID, user.ID) if err != nil { err = s.BE().CacheError(err) return } } }() pfu := provider.NewFissionUser(s.Ctx, cpn, channel) user, err = pfu.VisitUser( s.Req.GetUid(), s.Req.GetPlatform(), s.Req.GetLang(), s.Req.GetLv(), s.Req.GetCustomParam(), s.Req.GetIp(), s.Req.GetCenterId(), s.Req.GetModuleId(), s._getDevice(cpn.ProjectID), s.wbu, ) if err != nil { return } s.changeLangMark, s.changeLvMark = pfu.GetChangeLangMark(), pfu.GetChangeLvMark() return } func (s *Visit) token(cpn *model.FissionCampaign, user *model.FissionUser) (err error) { res, err := app.NewCertifiedFUser().Token(s.Ctx, &c_fuserpb.TokenReq{ Id: user.ID, CampaignId: user.CampaignID, ChannelId: user.ChannelID, Pid: user.ParentID, IsView: user.IsView == mtype.Yes, Lang: utils.NotExistGetFirst[string](user.LangMark, cpn.GetLangMarks()), Lv: user.UserLevelMark, ShowLang: user.LangMark, Country: user.UserCountry, Tz: consts.CampaignTz, TzOffset: s.cpnControl.GetTz(), }) if err != nil { return } s.Res.Id = user.ID s.Res.HashId = user.HashID s.Res.Token = res.GetToken() s.Res.Expired = res.GetExpired() s.Res.IsView = int32(user.IsView) return } func (s *Visit) setLink(cpn *model.FissionCampaign, channel *model.FissionCampaignChannel, user *model.FissionUser) (err error) { if user.ShareLink != "" && !s.changeLvMark && !s.changeLangMark { return } project, err := finder.Project(s.Ctx, cpn.ProjectID) if err != nil { err = s.BE().CacheError(err) return } // 把分享链接变成短链 shareLink, err := s._shareLink(cpn, project, channel, user) if err != nil { return } res, _ := app.NewShortLinkNameLink().CreateShortLink(s.Ctx, &linkpb.CreateShortLinkReq{ LongLink: shareLink, Domain: project.Domain, }) if res.GetShortLink() == "" { return } m := s.GetDao().FissionUser _, _ = m.WithContext(s.Ctx).Where(m.ID.Eq(user.ID)).UpdateSimple(m.ShareLink.Value(res.GetShortLink())) ms := s.GetDao().FissionUser.SubTable(cpn.ID) _, _ = ms.WithContext(s.Ctx).Where(ms.ID.Eq(user.ID)).UpdateSimple(ms.ShareLink.Value(res.GetShortLink())) s.AddAfterRun(func() (err error) { if s.clearUser { return } // 清除缓存 _ = cache.NewFissionUser(s.Ctx, cpn.ID).Clear(user) s.clearUser = true return }) return } // 获取分享链接 func (s *Visit) _shareLink(cpn *model.FissionCampaign, project *model.Project, appChannel *model.FissionCampaignChannel, user *model.FissionUser) (link string, err error) { conf, err := cache.NewCampaignConfig(s.Ctx).FindByCampaignId(cpn.ID) if err != nil { err = s.BE().CacheError(err) return } if project.Scene == mtype.ProjectSceneWeb { link = blink.NewCampaignLink( project.Domain, cpn.HashID, appChannel.Mark, blink.SetSubUserId(s.Req.GetUid()), blink.SetScene(project.Scene), blink.SetLang(user.LangMark), blink.SetLevel(user.LevelMark), ).CampaignWebShareLink() return } if conf.HasWeb == mtype.No { link = blink.NewCampaignLink( project.Domain, cpn.HashID, appChannel.Mark, blink.SetSubUserId(s.Req.GetUid()), blink.SetLang(user.LangMark), blink.SetLevel(user.LevelMark), ).CampaignDownloadLink() return } m := s.GetDao().FissionCampaignChannel var webChannel *model.FissionCampaignChannel if s.wbu == nil { webChannel, err = m.WithContext(s.Ctx).Where( m.CampaignID.Eq(cpn.ID), m.IsDefault.Eq(mtype.Yes), m.IsDel.Eq(mtype.No), m.CType.Eq(mtype.FissionCampaignChannelTypeWeb), ).Take() } else { webChannel, err = m.WithContext(s.Ctx).Where( m.ID.Eq(s.wbu.ChannelID), ).Take() } if err = dbcheck.DbError(err); err != nil { err = s.BE().MysqlError(err) return } if webChannel == nil { return } link = blink.NewCampaignLink( project.Domain, cpn.HashID, webChannel.Mark, blink.SetSubUserId(s.Req.GetUid()), blink.SetLang(user.LangMark), blink.SetLevel(user.LevelMark), ).CampaignWebLink() return } func (s *Visit) _cert(project int64) (err error) { if s.Req.GetUid() == consts.FissionViewer { return } // 数据验签 cert, err := app.NewCertifiedFUser().CertUser(s.Ctx, &c_fuserpb.CertUserReq{ ProjectId: project, UserId: s.Req.GetUid(), Lv: s.Req.GetLv(), Lang: s.Req.GetLang(), Time: s.Req.GetCert().GetTime(), Blackbox: s.Req.GetCert().GetBlackbox(), Version: s.Req.GetCert().GetVersion(), Platform: s.Req.GetCert().GetPlatform(), Token: s.Req.GetCert().GetToken(), }) if err != nil || !cert.GetOk() { err = workerr.UnauthorizedError return } return } func (s *Visit) _white(conf *model.FissionCampaignConfig, userId string) (err error) { if userId == consts.FissionViewer { return } if s.cpnControl.IsWait() && conf.HasWarmUp == mtype.No { return workerr.CNotRunError } if s.cpnControl.IsPre() { userIdList := strings.Split(conf.WhiteList, ";") for _, id := range userIdList { if userId == id { return } } return workerr.CNotRunError } return } func (s *Visit) _getDevice(projectId int64) *ddevicepb.FindBlackboxRes { if s.device == nil && s.Req.GetCert().GetBlackbox() != "" { s.device, _ = app.NewDeepLinkDevice().FindBlackbox(s.Ctx, &ddevicepb.FindBlackboxReq{ Blackbox: s.Req.GetCert().GetBlackbox(), ProjectId: projectId, }) } return s.device } // 是否有上级 func (s *Visit) _hasParent(cpn *model.FissionCampaign) (err error) { device := s._getDevice(cpn.ProjectID) if device == nil || device.GetDeviceId() == "" { return } //看看能不能找到device的参与数据 cc := cache.NewFissionUser(s.Ctx, cpn.ID) user, err := cc.FindByDeviceId(device.GetDeviceId()) if err != nil { err = s.BE().CacheError(err) return } if user != nil { s.Res.HasParent = user.ParentID > 0 return } if device.GetLastParentUserId() == "" { return } // 怀疑没入库,好这个上级用户是不是这个活动的,是就认为他有上级 user, err = cc.FindBySubUserId(device.GetLastParentUserId()) if err != nil { err = s.BE().CacheError(err) return } s.Res.HasParent = user != nil return } func (s *Visit) track(cpn *model.FissionCampaign, user *model.FissionUser) (err error) { inApp := fissionaction.NewMarkPoint(s.Ctx).InApp(user) if s.Req.GetCenterId() != "" { inApp.CenterDrainage(time.Now().Unix(), s.Req.GetCenterId(), s.Req.GetModuleId()) } inApp.View(time.Now().Unix(), s.Req.GetIp(), s.Req.GetOs(), s.Req.GetOsVersion(), s.Req.GetDeviceModel()) data, err := lockdo.Bytes(s.Ctx, ckey.FissionRewardPushOpenOnce(cpn.ID, mtype.FissionCampaignPushMarkVisit), func() (data []byte, err error) { pushM := s.GetDao().FissionCampaignPush push, err := pushM.WithContext(s.Ctx).Where(pushM.CampaignID.Eq(cpn.ID), pushM.Mark.Eq(mtype.FissionCampaignPushMarkVisit)).Take() if err = dbcheck.DbError(err); err != nil { err = s.BE().MysqlError(err) return } if push == nil { push = &model.FissionCampaignPush{} } return jsonm.Marshal(push) }) if err != nil { err = s.BE().CacheError(err) return } var push = &model.FissionCampaignPush{} err = jsonm.Unmarshal(data, push) if err != nil { return } if push.Open != mtype.Yes { return } p, err := pusher.NewPusher(s.Ctx, cpn) if err != nil { return } err = p.Visit(user, time.Now()) if err != nil { err = s.BE().MysqlError(err) } return }