You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

442 lines
10 KiB
Go

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
}