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.

539 lines
12 KiB
Go

package provider
import (
"context"
"joybuywork/internal/app"
"joybuywork/internal/consts"
"joybuywork/internal/consts/ckey"
"joybuywork/internal/plugins/jsonm"
"joybuywork/internal/repository/cache"
"joybuywork/internal/repository/dao"
"joybuywork/internal/repository/model"
"joybuywork/internal/repository/mtype"
"joybuywork/internal/repository/withdefault"
"joybuywork/internal/utils"
"joybuywork/internal/utils/logic"
"joybuywork/internal/utils/merr"
"joybuywork/internal/utils/verify"
"fmt"
"strings"
"time"
"joybuywork/proto/go_proto/workerr"
"gits.branchcn.com/backend/microcode/plugins/derivative/lock"
"gorm.io/gorm/clause"
)
type FissionUserAttr struct {
logic.Context
user *model.FissionUser
attr map[string]*model.FissionUserAttr
}
func NewFissionUserAttr(ctx context.Context, user *model.FissionUser) *FissionUserAttr {
attr := &FissionUserAttr{
user: user,
}
attr.Init(ctx, dao.Q, merr.NewBE(ctx))
return attr
}
func (s *FissionUserAttr) GetAttr(mark string) (*model.FissionUserAttr, error) {
if s.attr != nil {
return s.attr[mark], nil
}
var attrMarks = []string{mtype.FissionUserAttrMarkPlatform, mtype.FissionUserAttrMarkLang, mtype.FissionUserAttrMarkUserLv}
s.attr = make(map[string]*model.FissionUserAttr, len(attrMarks))
for _, v := range attrMarks {
attr, err := cache.NewFissionUserAttr(s.Ctx).FindByUniqIdx(s.user.ID, v)
if err != nil {
return nil, s.BE().CacheError(err)
}
s.attr[v] = attr
}
return s.attr[mark], nil
}
func (s *FissionUserAttr) WithUser(platform, lang, levelMark, lvMarks, country, centerHashId, moduleId string, channelId int64) (err error) {
user := s.user
var attrs []*model.FissionUserAttr
if lang != "" {
attrs = append(attrs, withdefault.FissionUserAttr(&model.FissionUserAttr{
CampaignID: user.CampaignID,
UserID: user.ID,
Attr: mtype.FissionUserAttrMarkLang,
Value: user.LangMark,
Values: user.LangMark,
}))
}
if levelMark != "" {
setLv := strings.Split(lvMarks, ",")
attrs = append(attrs, withdefault.FissionUserAttr(&model.FissionUserAttr{
CampaignID: user.CampaignID,
UserID: user.ID,
Attr: mtype.FissionUserAttrMarkUserLv,
Value: utils.Ternary[string](verify.InArray(levelMark, setLv...), levelMark, setLv[0]),
Values: lvMarks,
}))
}
if country != "" {
attrs = append(attrs, withdefault.FissionUserAttr(&model.FissionUserAttr{
CampaignID: user.CampaignID,
UserID: user.ID,
Attr: mtype.FissionUserAttrMarkCountry,
Value: country,
Values: country,
}))
}
if platform != "" {
platform = utils.SupportPlatform(platform)
attrs = append(attrs, withdefault.FissionUserAttr(&model.FissionUserAttr{
CampaignID: user.CampaignID,
UserID: user.ID,
Attr: mtype.FissionUserAttrMarkPlatform,
Value: platform,
Values: platform,
}))
}
if channelId != 0 {
webChId := fmt.Sprint(channelId)
attrs = append(attrs, withdefault.FissionUserAttr(&model.FissionUserAttr{
CampaignID: user.CampaignID,
UserID: user.ID,
Attr: mtype.FissionUserAttrMarkWebChannel,
Value: webChId,
Values: webChId,
}))
}
if centerHashId != "" {
attrs = append(attrs, withdefault.FissionUserAttr(&model.FissionUserAttr{
CampaignID: user.CampaignID,
UserID: user.ID,
Attr: mtype.FissionUserAttrMarkCenter,
Value: centerHashId,
Values: centerHashId,
}))
}
if moduleId != "" {
attrs = append(attrs, withdefault.FissionUserAttr(&model.FissionUserAttr{
CampaignID: user.CampaignID,
UserID: user.ID,
Attr: mtype.FissionUserAttrMarkCenterModule,
Value: moduleId,
Values: moduleId,
}))
}
if len(attrs) == 0 {
return
}
return s.creates(attrs...)
}
// Platform 更新平台
func (s *FissionUserAttr) Platform(platform string) (err error) {
if platform == "" || s.ignore() {
return
}
// 用户关联的平台
platform = utils.SupportPlatform(platform)
pfAttr, err := s.firstOrCreate(mtype.FissionUserAttrMarkPlatform, platform, platform)
if err != nil {
return
}
// 如果没更新,或者平台是其他,就不用处理了
if platform == pfAttr.Value || platform == consts.PlatformOther {
return
}
return s.update(pfAttr, platform)
}
// WebChannel 更新站外渠道
func (s *FissionUserAttr) WebChannel(channelId int64) (err error) {
if channelId == 0 || s.ignore() {
return
}
webChId := fmt.Sprint(channelId)
wbcAttr, err := s.firstOrCreate(mtype.FissionUserAttrMarkWebChannel, webChId, webChId)
if err != nil {
return
}
// 如果没更新,就不用处理了
if webChId == wbcAttr.Value {
return
}
return s.update(wbcAttr, webChId)
}
// Country 更新国家属性
func (s *FissionUserAttr) Country(country string) (err error) {
if country == "" || s.ignore() {
return
}
// 用户关联的国家
pfAttr, err := s.firstOrCreate(mtype.FissionUserAttrMarkCountry, country, country)
if err != nil {
return
}
// 如果没更新,或者平台是其他,就不用处理了
if country == pfAttr.Value {
return
}
return s.update(pfAttr, country)
}
// UserLv 更新用户等级
func (s *FissionUserAttr) UserLv(userLv string, setLv []string) (err error) {
if userLv == "" || s.ignore() {
return
}
// 用户关联的用户等级
attrVal := utils.Ternary[string](verify.InArray[string](userLv, setLv...), userLv, setLv[0])
values := strings.Join(setLv, ",")
pfAttr, err := s.firstOrCreate(mtype.FissionUserAttrMarkUserLv, attrVal, values)
if err != nil {
return
}
// 如果没更新,或者平台是其他,就不用处理了
if attrVal == pfAttr.Value && verify.AllInArray(setLv, pfAttr.GetValues()) {
return
}
return s.update(pfAttr, setLv...)
}
// Lang 更新语言
func (s *FissionUserAttr) Lang(lang string) (err error) {
if lang == "" || s.ignore() {
return
}
// 用户关联的语言
pfAttr, err := s.firstOrCreate(mtype.FissionUserAttrMarkLang, lang, lang)
if err != nil {
return
}
// 如果没更新,或者平台是其他,就不用处理了
if lang == pfAttr.Value {
return
}
return s.update(pfAttr, lang)
}
// Center 更新任务中心来源
func (s *FissionUserAttr) Center(centerHashId string) (err error) {
if centerHashId == "" || s.ignore() {
return
}
// 用户关联的任务中心
pfAttr, err := s.firstOrCreate(mtype.FissionUserAttrMarkCenter, centerHashId, centerHashId)
if err != nil {
return
}
// 如果没更新,就不用处理了
if centerHashId == pfAttr.Value {
return
}
return s.update(pfAttr, centerHashId)
}
// CenterModule 更新任务中心模块来源
func (s *FissionUserAttr) CenterModule(moduleId string) (err error) {
if moduleId == "" || s.ignore() {
return
}
// 用户关联的任务中心模块
pfAttr, err := s.firstOrCreate(mtype.FissionUserAttrMarkCenterModule, moduleId, moduleId)
if err != nil {
return
}
// 如果没更新,就不用处理了
if moduleId == pfAttr.Value {
return
}
return s.update(pfAttr, moduleId)
}
func (s *FissionUserAttr) firstOrCreate(attrMark, value, values string) (attr *model.FissionUserAttr, err error) {
user := s.user
attr, err = cache.NewFissionUserAttr(s.Ctx).FindByUniqIdx(user.ID, attrMark, cache.WithNilSet(func() ([]byte, error) {
createAttr := withdefault.FissionUserAttr(&model.FissionUserAttr{
CampaignID: user.CampaignID,
UserID: user.ID,
Attr: attrMark,
Value: value,
Values: values,
})
err = s.creates(createAttr)
if err != nil {
return nil, err
}
return jsonm.Marshal(createAttr)
}))
if err != nil {
err = s.BE().CacheError(err)
return
}
return
}
func (s *FissionUserAttr) creates(attrs ...*model.FissionUserAttr) (err error) {
err = s.GetDao().FissionUserAttr.WithContext(s.Ctx).Clauses(
clause.OnConflict{
DoNothing: true,
}).Create(attrs...)
if err != nil {
err = s.BE().MysqlError(err)
return
}
for _, attr := range attrs {
if s.canTotalAttr(attr.Attr) {
_ = s.changeTotal(attr.Attr, attr.Value, "")
}
}
return
}
func (s *FissionUserAttr) createsJ(attrs ...*model.FissionUserJattr) (err error) {
err = s.GetDao().FissionUserJattr.WithContext(s.Ctx).Clauses(
clause.OnConflict{
DoNothing: true,
}).Create(attrs...)
if err != nil {
err = s.BE().MysqlError(err)
return
}
return
}
func (s *FissionUserAttr) update(attr *model.FissionUserAttr, vals ...string) (err error) {
attrM := s.GetDao().FissionUserAttr
attrVals := attr.GetValues()
for _, val := range vals {
if !verify.InArray(val, attrVals...) {
attrVals = append(attrVals, val)
}
}
_, err = attrM.WithContext(s.Ctx).Where(attrM.ID.Eq(attr.ID)).UpdateSimple(
attrM.Value.Value(vals[0]),
attrM.Values.Value(strings.Join(attrVals, ",")),
)
if err != nil {
err = s.BE().MysqlError(err)
return
}
if s.canTotalAttr(attr.Attr) {
_ = s.changeTotal(attr.Attr, vals[0], attr.Value)
}
// 清除缓存
_ = cache.NewFissionUserAttr(s.Ctx).Clear(attr)
return
}
func (s *FissionUserAttr) changeTotal(attr string, newVal, oldVal string) (err error) {
m := s.GetDao().FissionUserAttrTotal
if newVal != "" {
var id int64
id, err = s.getTotalId(attr, newVal)
if err != nil {
return
}
_, err = m.WithContext(s.Ctx).Where(m.ID.Eq(id)).UpdateSimple(m.Num.Add(1))
if err != nil {
err = s.BE().MysqlError(err)
return
}
}
if oldVal != "" {
var id int64
id, err = s.getTotalId(attr, oldVal)
if err != nil {
return
}
_, err = m.WithContext(s.Ctx).Where(m.ID.Eq(id)).UpdateSimple(m.Num.Sub(1))
if err != nil {
err = s.BE().MysqlError(err)
return
}
}
return
}
func (s *FissionUserAttr) ignore() bool {
return s.user.IsView == mtype.Yes
}
func (s *FissionUserAttr) canTotalAttr(attr string) bool {
return verify.InArray[string](attr, mtype.FissionUserAttrMarkPlatform)
}
func (s *FissionUserAttr) getTotalId(attr, val string) (id int64, err error) {
cc := cache.NewFissionUserAttrTotal(s.Ctx)
id, err = cc.FindByUniqIdx(s.user.CampaignID, attr, val)
if err != nil {
err = s.BE().CacheError(err)
return
}
if id != 0 {
return
}
lc := app.NewFollower(s.Ctx, ckey.FissionUserAttrCreateOnce(s.user.CampaignID, attr, val), lock.SetExpire(10*time.Second)).Lock()
defer lc.Release()
if lc.Error() != nil {
err = workerr.BusyError
return
}
id, err = cc.FindByUniqIdx(s.user.CampaignID, attr, val)
if err != nil {
err = s.BE().CacheError(err)
return
}
if id != 0 {
return
}
total := withdefault.FissionUserAttrTotal(&model.FissionUserAttrTotal{
CampaignID: s.user.CampaignID,
Attr: attr,
Val: val,
Num: 0,
})
err = s.GetDao().FissionUserAttrTotal.WithContext(s.Ctx).Create(total)
if err != nil {
err = s.BE().MysqlError(err)
return
}
id = total.ID
return
}
func (s *FissionUserAttr) CustomParam(paramStr string) (err error) {
if paramStr == "" || s.ignore() {
return
}
pfAttr, err := s.firstOrCreateJ(mtype.FissionUserAttrMarkCustomParam, paramStr)
if err != nil {
return
}
// 如果没更新,就不用处理了
if paramStr == pfAttr.Value && verify.InArray[string](paramStr, pfAttr.GetValues()...) {
return
}
return s.updateJ(pfAttr, paramStr)
}
func (s *FissionUserAttr) firstOrCreateJ(attrMark string, values ...string) (attr *model.FissionUserJattr, err error) {
user := s.user
valj, _ := jsonm.ToSliceString(values)
attr, err = cache.NewFissionUserJattr(s.Ctx).FindByUniqIdx(user.ID, attrMark, cache.WithNilSet(func() ([]byte, error) {
createAttr := withdefault.FissionUserJattr(&model.FissionUserJattr{
CampaignID: user.CampaignID,
UserID: user.ID,
Attr: attrMark,
Value: values[0],
Values: valj,
})
err = s.createsJ(createAttr)
if err != nil {
return nil, err
}
return jsonm.Marshal(createAttr)
}))
if err != nil {
err = s.BE().CacheError(err)
return
}
return
}
func (s *FissionUserAttr) updateJ(attr *model.FissionUserJattr, vals ...string) (err error) {
attrM := s.GetDao().FissionUserJattr
attrVals := attr.GetValues()
for _, val := range vals {
if !verify.InArray(val, attrVals...) {
attrVals = append(attrVals, val)
}
}
values, _ := jsonm.ToSliceString(attrVals)
_, err = attrM.WithContext(s.Ctx).Where(attrM.ID.Eq(attr.ID)).UpdateSimple(
attrM.Value.Value(vals[0]),
attrM.Values.Value(values),
)
if err != nil {
err = s.BE().MysqlError(err)
return
}
// 清除缓存
_ = cache.NewFissionUserJattr(s.Ctx).Clear(attr)
return
}