201 lines
7.5 KiB
Go
201 lines
7.5 KiB
Go
package business
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"strings"
|
|
|
|
"gorm.io/gorm"
|
|
"kra/internal/biz/business"
|
|
)
|
|
|
|
type channelPO struct {
|
|
ID uint64
|
|
SourceDB string `gorm:"column:source_db"`
|
|
Account, Nickname, ParentName, RealName string
|
|
PromoteLevel, RegisterType, Status, LockStatus *int
|
|
ParentID, TopPromoteID, BusierID uint64
|
|
CreateTime *int64
|
|
LastLoginTime *int64 `gorm:"column:last_login_time"`
|
|
}
|
|
|
|
func (channelPO) TableName() string { return "tab_promote" }
|
|
func toBizChannel(p channelPO) *business.Channel {
|
|
return &business.Channel{ChannelKey: business.ChannelKey{SourceDB: p.SourceDB, ID: p.ID}, Account: p.Account, Nickname: p.Nickname, ParentName: p.ParentName, RealName: p.RealName, Level: p.PromoteLevel, RegisterType: p.RegisterType, Status: p.Status, LockStatus: p.LockStatus, ParentID: p.ParentID, TopPromoteID: p.TopPromoteID, BusierID: p.BusierID, CreatedUnix: p.CreateTime, LastLoginUnix: p.LastLoginTime}
|
|
}
|
|
|
|
type channelRepo struct{ data Provider }
|
|
|
|
func NewChannelRepo(data Provider) business.ChannelRepo { return &channelRepo{data: data} }
|
|
|
|
func channelBindingQuery(db *gorm.DB, scope business.UserScope, filter business.ChannelFilter) *gorm.DB {
|
|
q := db.Table("sys_user_bind_platform b").Joins("LEFT JOIN sys_users u ON u.id=b.user_id").Where("b.status = ?", "0")
|
|
if !scope.All {
|
|
q = applyUserScope(q.Where("u.deleted_at IS NULL"), scope, "u.")
|
|
}
|
|
if filter.BusierUserID != nil {
|
|
q = q.Where("b.user_id = ?", *filter.BusierUserID)
|
|
}
|
|
if len(filter.Sources) > 0 {
|
|
q = q.Where("b.source_db IN ?", filter.Sources)
|
|
}
|
|
if keyword := strings.ToLower(strings.TrimSpace(filter.BusierAccount)); keyword != "" {
|
|
q = q.Where("(INSTR(LOWER(b.platform_busier_account),?) > 0 OR INSTR(LOWER(u.username),?) > 0)", keyword, keyword)
|
|
}
|
|
return q
|
|
}
|
|
func (r *channelRepo) Bindings(ctx context.Context, scope business.UserScope, source string) ([]*business.Binding, error) {
|
|
var pos []bindingPO
|
|
if err := channelBindingQuery(r.data.DB().WithContext(ctx), scope, business.ChannelFilter{Sources: []string{source}}).Select("b.*").Order("b.user_id,b.source_db,b.platform_busier_id").Scan(&pos).Error; err != nil {
|
|
return nil, business.ErrStorage
|
|
}
|
|
rows := make([]*business.Binding, 0, len(pos))
|
|
for _, po := range pos {
|
|
rows = append(rows, toBizBinding(po))
|
|
}
|
|
return rows, nil
|
|
}
|
|
func (r *channelRepo) List(ctx context.Context, scope business.UserScope, filter business.ChannelFilter, options ...business.ListOption) (*business.ChannelPage, error) {
|
|
db := r.data.DB().WithContext(ctx)
|
|
page := &business.ChannelPage{Rows: []*business.Channel{}, Available: true}
|
|
bindings := channelBindingQuery(db, scope, filter)
|
|
constrain := !scope.All || filter.BusierUserID != nil || filter.BusierAccount != ""
|
|
if constrain {
|
|
var count int64
|
|
if err := bindings.Count(&count).Error; err != nil {
|
|
return nil, business.ErrStorage
|
|
}
|
|
if count == 0 {
|
|
return page, nil
|
|
}
|
|
}
|
|
available, err := businessTableAvailable(db, "tab_promote")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if !available {
|
|
page.Available = false
|
|
return page, nil
|
|
}
|
|
q := db.Table("tab_promote p")
|
|
if constrain {
|
|
q = q.Where("EXISTS (?)", bindings.Select("1").Where("b.source_db=p.source_db AND b.platform_busier_id=p.busier_id"))
|
|
}
|
|
if len(filter.Sources) > 0 {
|
|
q = q.Where("p.source_db IN ?", filter.Sources)
|
|
}
|
|
if filter.Keyword != "" {
|
|
q = q.Where("p.account LIKE ?", "%"+filter.Keyword+"%")
|
|
}
|
|
for _, field := range []struct {
|
|
column string
|
|
value *int
|
|
}{{"promote_level", filter.Level}, {"register_type", filter.RegisterType}, {"status", filter.Status}, {"lock_status", filter.LockStatus}} {
|
|
if field.value != nil {
|
|
q = q.Where("p."+field.column+" = ?", *field.value)
|
|
}
|
|
}
|
|
if err := q.Count(&page.Total).Error; err != nil {
|
|
return nil, business.ErrStorage
|
|
}
|
|
var pos []channelPO
|
|
o := business.NewListOptions(options...)
|
|
if err := q.Select("p.id,p.source_db,p.account,p.nickname,p.parent_name,p.real_name,p.promote_level,p.register_type,p.status,p.lock_status,p.parent_id,p.top_promote_id,p.busier_id").Order("p.create_time DESC,p.id DESC,p.source_db ASC").Offset(o.Offset).Limit(o.Limit).Scan(&pos).Error; err != nil {
|
|
return nil, business.ErrStorage
|
|
}
|
|
if len(pos) == 0 {
|
|
return page, nil
|
|
}
|
|
pairs := make([][]any, 0, len(pos))
|
|
for _, po := range pos {
|
|
pairs = append(pairs, []any{po.SourceDB, po.BusierID})
|
|
}
|
|
var bound []struct {
|
|
SourceDB string `gorm:"column:source_db"`
|
|
PlatformBusierID uint64
|
|
UserID uint
|
|
PlatformBusierAccount, UserName string
|
|
}
|
|
if err := channelBindingQuery(db, scope, filter).Select("b.source_db,b.platform_busier_id,b.user_id,b.platform_busier_account,u.username AS user_name").Where("(b.source_db,b.platform_busier_id) IN ?", pairs).Order("b.user_id").Scan(&bound).Error; err != nil {
|
|
return nil, business.ErrStorage
|
|
}
|
|
byKey := map[business.PlatformKey]int{}
|
|
for i, b := range bound {
|
|
key := business.PlatformKey{SourceDB: b.SourceDB, BusierID: b.PlatformBusierID}
|
|
if _, ok := byKey[key]; !ok {
|
|
byKey[key] = i
|
|
}
|
|
}
|
|
for _, po := range pos {
|
|
c := toBizChannel(po)
|
|
if i, ok := byKey[business.PlatformKey{SourceDB: po.SourceDB, BusierID: po.BusierID}]; ok {
|
|
b := bound[i]
|
|
c.BusierUserID = &b.UserID
|
|
c.BindingAccount = b.PlatformBusierAccount
|
|
c.BindingUserName = b.UserName
|
|
}
|
|
page.Rows = append(page.Rows, c)
|
|
}
|
|
return page, nil
|
|
}
|
|
func (r *channelRepo) Find(ctx context.Context, scope business.UserScope, key business.ChannelKey) (*business.Channel, error) {
|
|
db := r.data.DB().WithContext(ctx)
|
|
available, err := businessTableAvailable(db, "tab_promote")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if !available {
|
|
return nil, business.ErrChannelUnavailable
|
|
}
|
|
var po channelPO
|
|
if err := db.Where("source_db = ? AND id = ?", key.SourceDB, key.ID).Take(&po).Error; err != nil {
|
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
|
return nil, business.ErrChannelNotFound
|
|
}
|
|
return nil, business.ErrStorage
|
|
}
|
|
if !scope.All {
|
|
var count int64
|
|
if err := channelBindingQuery(db, scope, business.ChannelFilter{Sources: []string{key.SourceDB}}).Where("b.platform_busier_id = ?", po.BusierID).Count(&count).Error; err != nil {
|
|
return nil, business.ErrStorage
|
|
}
|
|
if count == 0 {
|
|
return nil, business.ErrChannelScope
|
|
}
|
|
}
|
|
return toBizChannel(po), nil
|
|
}
|
|
func channelPairs(keys []business.ChannelKey) [][]any {
|
|
pairs := make([][]any, 0, len(keys))
|
|
for _, key := range keys {
|
|
pairs = append(pairs, []any{key.SourceDB, key.ID})
|
|
}
|
|
return pairs
|
|
}
|
|
func (r *channelRepo) StatChannels(ctx context.Context, roots []*business.Channel) ([]*business.Channel, error) {
|
|
keys := make([]business.ChannelKey, 0, len(roots))
|
|
for _, root := range roots {
|
|
if root.Level != nil && *root.Level < 3 {
|
|
keys = append(keys, root.ChannelKey)
|
|
}
|
|
}
|
|
rows := []*business.Channel{}
|
|
seen := map[business.ChannelKey]bool{}
|
|
for start := 0; start < len(keys); start += 200 {
|
|
pairs := channelPairs(keys[start:min(start+200, len(keys))])
|
|
var pos []channelPO
|
|
err := r.data.DB().WithContext(ctx).Table("tab_promote").Select("id,source_db,promote_level,parent_id,top_promote_id").Where("(source_db,parent_id) IN ? OR (source_db,top_promote_id) IN ?", pairs, pairs).Scan(&pos).Error
|
|
if err != nil {
|
|
return nil, business.ErrStorage
|
|
}
|
|
for _, po := range pos {
|
|
c := toBizChannel(po)
|
|
if !seen[c.ChannelKey] {
|
|
rows = append(rows, c)
|
|
seen[c.ChannelKey] = true
|
|
}
|
|
}
|
|
}
|
|
return rows, nil
|
|
}
|