chore: 并入 iotlcm-admin-svr 历史到 admin-svr/(原提交 49818c6)
This commit is contained in:
@@ -0,0 +1,588 @@
|
||||
package warningnotify
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/consts"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/dao"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/library/contexts"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/model"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/model/entity"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/service"
|
||||
|
||||
"github.com/gogf/gf/v2/encoding/gjson"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
const (
|
||||
messageTypeSystem = 1
|
||||
sendUserTypeAgent = 1
|
||||
sendUserTypeTerminal = 2
|
||||
simTerminalTable = "t_sim_terminal"
|
||||
terminalTable = "t_terminal"
|
||||
defaultPlatformTitle = "预警提醒"
|
||||
defaultPlatformContent = "您有新的预警消息,请登录平台查看。"
|
||||
)
|
||||
|
||||
type platformRecipientGroup struct {
|
||||
SendUserType int
|
||||
UserIDs []int64
|
||||
}
|
||||
|
||||
type platformDelivery struct {
|
||||
Group platformRecipientGroup
|
||||
Batch Batch
|
||||
}
|
||||
|
||||
type terminalUserCardRow struct {
|
||||
UserID int64 `orm:"user_id"`
|
||||
ICCID string `orm:"iccid"`
|
||||
MSISDN string `orm:"msisdn"`
|
||||
}
|
||||
|
||||
// MessageCenterSender writes platform warnings through the message center service.
|
||||
// Email and SMS warnings are sent through their configured external services.
|
||||
type MessageCenterSender struct {
|
||||
Fallback Sender
|
||||
}
|
||||
|
||||
func init() {
|
||||
UseMessageCenterSender()
|
||||
}
|
||||
|
||||
func UseMessageCenterSender() {
|
||||
SetSender(MessageCenterSender{Fallback: LogSender{}})
|
||||
}
|
||||
|
||||
func (s MessageCenterSender) Send(ctx context.Context, batch Batch) error {
|
||||
if ctx == nil {
|
||||
ctx = context.Background()
|
||||
}
|
||||
if len(batch.Items) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
switch batch.Method {
|
||||
case MethodPlatform:
|
||||
return s.sendPlatform(ctx, batch)
|
||||
case MethodEmail:
|
||||
return s.sendEmail(ctx, batch)
|
||||
case MethodSMS:
|
||||
return s.sendSMS(ctx, batch)
|
||||
case MethodWechat:
|
||||
return s.sendWechat(ctx, batch)
|
||||
default:
|
||||
return s.fallback().Send(ctx, batch)
|
||||
}
|
||||
}
|
||||
|
||||
func (s MessageCenterSender) sendPlatform(ctx context.Context, batch Batch) error {
|
||||
if err := s.writePlatform(ctx, batch); err != nil {
|
||||
g.Log().Errorf(
|
||||
ctx,
|
||||
"WarningNotify platform message write failed, business:%s, tenantId:%s, deptId:%d, category:%s, stage:%d, count:%d, err:%+v",
|
||||
batch.Business,
|
||||
batch.TenantID,
|
||||
batch.DeptID,
|
||||
batch.Category,
|
||||
batch.WarnStage,
|
||||
len(batch.Items),
|
||||
err,
|
||||
)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s MessageCenterSender) sendEmail(ctx context.Context, batch Batch) error {
|
||||
if err := sendWarningEmail(ctx, batch); err != nil {
|
||||
g.Log().Errorf(
|
||||
ctx,
|
||||
"WarningNotify email send failed, business:%s, tenantId:%s, deptId:%d, category:%s, stage:%d, recipients:%s, count:%d, err:%+v",
|
||||
batch.Business,
|
||||
batch.TenantID,
|
||||
batch.DeptID,
|
||||
batch.Category,
|
||||
batch.WarnStage,
|
||||
strings.Join(batch.Recipients, ","),
|
||||
len(batch.Items),
|
||||
err,
|
||||
)
|
||||
return nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s MessageCenterSender) sendSMS(ctx context.Context, batch Batch) error {
|
||||
if err := sendWarningSMS(ctx, batch); err != nil {
|
||||
g.Log().Errorf(
|
||||
ctx,
|
||||
"WarningNotify SMS send failed, business:%s, tenantId:%s, deptId:%d, category:%s, stage:%d, recipients:%s, count:%d, err:%+v",
|
||||
batch.Business,
|
||||
batch.TenantID,
|
||||
batch.DeptID,
|
||||
batch.Category,
|
||||
batch.WarnStage,
|
||||
strings.Join(batch.Recipients, ","),
|
||||
len(batch.Items),
|
||||
err,
|
||||
)
|
||||
return nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s MessageCenterSender) sendWechat(ctx context.Context, batch Batch) error {
|
||||
if err := sendWarningWechat(ctx, batch); err != nil {
|
||||
g.Log().Errorf(
|
||||
ctx,
|
||||
"WarningNotify wechat subscribe send failed, business:%s, tenantId:%s, deptId:%d, category:%s, stage:%d, count:%d, err:%+v",
|
||||
batch.Business,
|
||||
batch.TenantID,
|
||||
batch.DeptID,
|
||||
batch.Category,
|
||||
batch.WarnStage,
|
||||
len(batch.Items),
|
||||
err,
|
||||
)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s MessageCenterSender) fallback() Sender {
|
||||
if s.Fallback != nil {
|
||||
return s.Fallback
|
||||
}
|
||||
return LogSender{}
|
||||
}
|
||||
|
||||
func (s MessageCenterSender) writePlatform(ctx context.Context, batch Batch) error {
|
||||
deliveries, err := resolvePlatformDeliveries(ctx, batch)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(deliveries) == 0 {
|
||||
g.Log().Warningf(
|
||||
ctx,
|
||||
"WarningNotify platform message skipped, no recipients, business:%s, tenantId:%s, deptId:%d, category:%s, stage:%d, count:%d",
|
||||
batch.Business,
|
||||
batch.TenantID,
|
||||
batch.DeptID,
|
||||
batch.Category,
|
||||
batch.WarnStage,
|
||||
len(batch.Items),
|
||||
)
|
||||
return nil
|
||||
}
|
||||
|
||||
messageCtx := platformMessageContext(ctx, batch)
|
||||
for _, delivery := range deliveries {
|
||||
if len(delivery.Group.UserIDs) == 0 || len(delivery.Batch.Items) == 0 {
|
||||
continue
|
||||
}
|
||||
messageBatch := delivery.Batch
|
||||
applyContent(&messageBatch)
|
||||
if err := service.CommonTMessageLog().Edit(messageCtx, platformMessageParam(messageBatch, delivery.Group)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
g.Log().Infof(
|
||||
ctx,
|
||||
"WarningNotify platform message submitted, business:%s, tenantId:%s, deptId:%d, category:%s, stage:%d, groups:%d, count:%d",
|
||||
batch.Business,
|
||||
batch.TenantID,
|
||||
batch.DeptID,
|
||||
batch.Category,
|
||||
batch.WarnStage,
|
||||
len(deliveries),
|
||||
len(batch.Items),
|
||||
)
|
||||
return nil
|
||||
}
|
||||
|
||||
func resolvePlatformDeliveries(ctx context.Context, batch Batch) ([]platformDelivery, error) {
|
||||
if batch.prepared != nil {
|
||||
return []platformDelivery{{Group: *batch.prepared, Batch: batch}}, nil
|
||||
}
|
||||
deliveries := make([]platformDelivery, 0, 2)
|
||||
|
||||
agentUserIDs, err := queryAgentUserIDs(ctx, batch.TenantID, batch.DeptID, batch.CreatedBy, batch.Business)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(agentUserIDs) > 0 {
|
||||
deliveries = append(deliveries, platformDelivery{
|
||||
Group: platformRecipientGroup{
|
||||
SendUserType: sendUserTypeAgent,
|
||||
UserIDs: agentUserIDs,
|
||||
},
|
||||
Batch: batch,
|
||||
})
|
||||
} else if batch.Business == BusinessTrafficCutoff {
|
||||
g.Log().Warningf(ctx, "WarningNotify traffic cutoff skipped department recipients, tenantId:%s, deptId:%d, category:%s, stage:%d, count:%d", batch.TenantID, batch.DeptID, batch.Category, batch.WarnStage, len(batch.Items))
|
||||
}
|
||||
|
||||
if hasCardWarningItems(batch.Items) {
|
||||
deliveries = append(deliveries, resolveTerminalPlatformDeliveries(ctx, batch)...)
|
||||
}
|
||||
|
||||
return deliveries, nil
|
||||
}
|
||||
|
||||
func queryAgentUserIDs(ctx context.Context, tenantID string, deptID int64, createdBy int64, business string) ([]int64, error) {
|
||||
deptUserIDs := make([]int64, 0)
|
||||
creatorUserID := int64(0)
|
||||
if strings.TrimSpace(tenantID) == "" {
|
||||
return deptUserIDs, nil
|
||||
}
|
||||
|
||||
columns := dao.SysUser.Columns()
|
||||
if deptID > 0 {
|
||||
var users []entity.SysUser
|
||||
if err := dao.SysUser.Ctx(ctx).
|
||||
Fields(columns.UserId).
|
||||
Where(columns.TenantId, tenantID).
|
||||
Where(columns.DeptId, deptID).
|
||||
Where(columns.UserType, consts.SysUserTypeSys).
|
||||
Where(columns.Status, consts.SysDeptStatusNormal).
|
||||
Scan(&users); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, user := range users {
|
||||
deptUserIDs = append(deptUserIDs, user.UserId)
|
||||
}
|
||||
}
|
||||
|
||||
if business != BusinessTrafficCutoff && createdBy > 0 {
|
||||
var creator *entity.SysUser
|
||||
if err := dao.SysUser.Ctx(ctx).
|
||||
Fields(columns.UserId).
|
||||
Where(columns.TenantId, tenantID).
|
||||
Where(columns.UserId, createdBy).
|
||||
Where(columns.UserType, consts.SysUserTypeSys).
|
||||
Where(columns.Status, consts.SysDeptStatusNormal).
|
||||
Scan(&creator); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if creator != nil {
|
||||
creatorUserID = creator.UserId
|
||||
}
|
||||
}
|
||||
|
||||
return platformAgentRecipientIDs(business, deptUserIDs, creatorUserID), nil
|
||||
}
|
||||
|
||||
func platformAgentRecipientIDs(business string, deptUserIDs []int64, createdBy int64) []int64 {
|
||||
userIDs := make([]int64, 0, len(deptUserIDs)+1)
|
||||
seen := make(map[int64]struct{})
|
||||
for _, userID := range deptUserIDs {
|
||||
userIDs = appendUniqueInt64(userIDs, seen, userID)
|
||||
}
|
||||
if business != BusinessTrafficCutoff {
|
||||
userIDs = appendUniqueInt64(userIDs, seen, createdBy)
|
||||
}
|
||||
return userIDs
|
||||
}
|
||||
|
||||
func queryCreatedTerminalUserIDs(ctx context.Context, tenantID string, createdBy int64) ([]int64, error) {
|
||||
tenantID = strings.TrimSpace(tenantID)
|
||||
if tenantID == "" || createdBy <= 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
columns := dao.SysUser.Columns()
|
||||
var creator *entity.SysUser
|
||||
if err := dao.SysUser.Ctx(ctx).
|
||||
Fields(columns.UserId).
|
||||
Where(columns.TenantId, tenantID).
|
||||
Where(columns.UserId, createdBy).
|
||||
Where(columns.UserType, consts.SysUserTypeAPP).
|
||||
Where(columns.Status, consts.SysDeptStatusNormal).
|
||||
Scan(&creator); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if creator == nil || creator.UserId <= 0 {
|
||||
return nil, nil
|
||||
}
|
||||
return []int64{creator.UserId}, nil
|
||||
}
|
||||
|
||||
func resolveTerminalPlatformDeliveries(ctx context.Context, batch Batch) []platformDelivery {
|
||||
if batch.prepared != nil {
|
||||
return []platformDelivery{{Group: *batch.prepared, Batch: batch}}
|
||||
}
|
||||
itemsByUser := make(map[int64][]Event)
|
||||
seenByUser := make(map[int64]map[int]struct{})
|
||||
|
||||
appendCreatedTerminalEvents(ctx, batch, itemsByUser, seenByUser)
|
||||
|
||||
if err := appendRelatedTerminalEvents(ctx, batch, itemsByUser, seenByUser); err != nil {
|
||||
g.Log().Warningf(ctx, "WarningNotify query terminal users failed, tenantId:%s, deptId:%d, err:%+v", batch.TenantID, batch.DeptID, err)
|
||||
}
|
||||
|
||||
userIDs := make([]int64, 0, len(itemsByUser))
|
||||
for userID := range itemsByUser {
|
||||
userIDs = append(userIDs, userID)
|
||||
}
|
||||
sort.Slice(userIDs, func(i, j int) bool {
|
||||
return userIDs[i] < userIDs[j]
|
||||
})
|
||||
|
||||
deliveries := make([]platformDelivery, 0, len(userIDs))
|
||||
for _, userID := range userIDs {
|
||||
items := itemsByUser[userID]
|
||||
if userID <= 0 || len(items) == 0 {
|
||||
continue
|
||||
}
|
||||
terminalBatch := batch
|
||||
terminalBatch.Items = append([]Event(nil), items...)
|
||||
terminalBatch.WarnStage = highestStage(terminalBatch.Items)
|
||||
deliveries = append(deliveries, platformDelivery{
|
||||
Group: platformRecipientGroup{
|
||||
SendUserType: sendUserTypeTerminal,
|
||||
UserIDs: []int64{userID},
|
||||
},
|
||||
Batch: terminalBatch,
|
||||
})
|
||||
}
|
||||
return deliveries
|
||||
}
|
||||
|
||||
type indexedWarningEvent struct {
|
||||
Index int
|
||||
Event Event
|
||||
}
|
||||
|
||||
func appendCreatedTerminalEvents(ctx context.Context, batch Batch, itemsByUser map[int64][]Event, seenByUser map[int64]map[int]struct{}) {
|
||||
itemsByCreator := make(map[int64][]indexedWarningEvent)
|
||||
for index, item := range batch.Items {
|
||||
if item.ItemType != 1 {
|
||||
continue
|
||||
}
|
||||
createdBy := item.CreatedBy
|
||||
if createdBy <= 0 {
|
||||
createdBy = batch.CreatedBy
|
||||
}
|
||||
if createdBy <= 0 {
|
||||
continue
|
||||
}
|
||||
itemsByCreator[createdBy] = append(itemsByCreator[createdBy], indexedWarningEvent{Index: index, Event: item})
|
||||
}
|
||||
|
||||
creatorIDs := make([]int64, 0, len(itemsByCreator))
|
||||
for createdBy := range itemsByCreator {
|
||||
creatorIDs = append(creatorIDs, createdBy)
|
||||
}
|
||||
sort.Slice(creatorIDs, func(i, j int) bool {
|
||||
return creatorIDs[i] < creatorIDs[j]
|
||||
})
|
||||
|
||||
for _, createdBy := range creatorIDs {
|
||||
userIDs, err := queryCreatedTerminalUserIDs(ctx, batch.TenantID, createdBy)
|
||||
if err != nil {
|
||||
g.Log().Warningf(ctx, "WarningNotify query created terminal user failed, tenantId:%s, userId:%d, err:%+v", batch.TenantID, createdBy, err)
|
||||
continue
|
||||
}
|
||||
for _, userID := range userIDs {
|
||||
for _, item := range itemsByCreator[createdBy] {
|
||||
appendTerminalEvent(itemsByUser, seenByUser, userID, item.Index, item.Event)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func appendRelatedTerminalEvents(ctx context.Context, batch Batch, itemsByUser map[int64][]Event, seenByUser map[int64]map[int]struct{}) error {
|
||||
tenantID := strings.TrimSpace(batch.TenantID)
|
||||
if tenantID == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
iccidIndexes, msisdnIndexes := terminalCardEventIndexes(batch.Items)
|
||||
if len(iccidIndexes) == 0 && len(msisdnIndexes) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
if len(iccidIndexes) > 0 {
|
||||
rows, err := queryTerminalUserCardRowsByColumn(ctx, tenantID, "st.iccid", mapKeys(iccidIndexes))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
appendTerminalRows(itemsByUser, seenByUser, batch.Items, rows, iccidIndexes, msisdnIndexes)
|
||||
}
|
||||
if len(msisdnIndexes) > 0 {
|
||||
rows, err := queryTerminalUserCardRowsByColumn(ctx, tenantID, "st.msisdn", mapKeys(msisdnIndexes))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
appendTerminalRows(itemsByUser, seenByUser, batch.Items, rows, iccidIndexes, msisdnIndexes)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func queryTerminalUserCardRowsByColumn(ctx context.Context, tenantID string, column string, values []string) ([]terminalUserCardRow, error) {
|
||||
rows := make([]terminalUserCardRow, 0)
|
||||
if strings.TrimSpace(tenantID) == "" || len(values) == 0 {
|
||||
return rows, nil
|
||||
}
|
||||
for offset := 0; offset < len(values); offset += 500 {
|
||||
if err := ctx.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
end := min(offset+500, len(values))
|
||||
var page []terminalUserCardRow
|
||||
if err := g.DB().Model(simTerminalTable+" st").Ctx(ctx).Safe().
|
||||
LeftJoin(terminalTable+" t", "t.terminal_id = st.terminal_id AND t.tenant_id = st.tenant_id").
|
||||
LeftJoin(dao.SysUser.Table()+" u", "(u.user_id = t.leader OR u.user_id = st.terminal_id) AND u.tenant_id = st.tenant_id").
|
||||
Fields("DISTINCT u.user_id, st.iccid, st.msisdn").
|
||||
Where("st.tenant_id", tenantID).
|
||||
Where("u.user_type", consts.SysUserTypeAPP).
|
||||
Where("u.status", consts.SysDeptStatusNormal).
|
||||
WhereIn(column, values[offset:end]).
|
||||
Scan(&page); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rows = append(rows, page...)
|
||||
}
|
||||
return rows, nil
|
||||
}
|
||||
|
||||
func hasCardWarningItems(items []Event) bool {
|
||||
for _, item := range items {
|
||||
if item.ItemType == 1 {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func terminalCardEventIndexes(items []Event) (map[string][]int, map[string][]int) {
|
||||
iccidIndexes := make(map[string][]int)
|
||||
msisdnIndexes := make(map[string][]int)
|
||||
for index, item := range items {
|
||||
if item.ItemType != 1 {
|
||||
continue
|
||||
}
|
||||
itemCode := strings.TrimSpace(item.ItemCode)
|
||||
msisdn := strings.TrimSpace(item.MSISDN)
|
||||
if itemCode != "" {
|
||||
iccidIndexes[itemCode] = append(iccidIndexes[itemCode], index)
|
||||
}
|
||||
if msisdn != "" {
|
||||
msisdnIndexes[msisdn] = append(msisdnIndexes[msisdn], index)
|
||||
}
|
||||
}
|
||||
return iccidIndexes, msisdnIndexes
|
||||
}
|
||||
|
||||
func appendTerminalRows(itemsByUser map[int64][]Event, seenByUser map[int64]map[int]struct{}, items []Event, rows []terminalUserCardRow, iccidIndexes map[string][]int, msisdnIndexes map[string][]int) {
|
||||
for _, row := range rows {
|
||||
if row.UserID <= 0 {
|
||||
continue
|
||||
}
|
||||
for _, index := range iccidIndexes[strings.TrimSpace(row.ICCID)] {
|
||||
appendTerminalEvent(itemsByUser, seenByUser, row.UserID, index, items[index])
|
||||
}
|
||||
for _, index := range msisdnIndexes[strings.TrimSpace(row.MSISDN)] {
|
||||
appendTerminalEvent(itemsByUser, seenByUser, row.UserID, index, items[index])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func appendAllCardEvents(itemsByUser map[int64][]Event, seenByUser map[int64]map[int]struct{}, userID int64, items []Event) {
|
||||
for index, item := range items {
|
||||
if item.ItemType != 1 {
|
||||
continue
|
||||
}
|
||||
appendTerminalEvent(itemsByUser, seenByUser, userID, index, item)
|
||||
}
|
||||
}
|
||||
|
||||
func appendTerminalEvent(itemsByUser map[int64][]Event, seenByUser map[int64]map[int]struct{}, userID int64, index int, item Event) {
|
||||
if userID <= 0 {
|
||||
return
|
||||
}
|
||||
seen := seenByUser[userID]
|
||||
if seen == nil {
|
||||
seen = make(map[int]struct{})
|
||||
seenByUser[userID] = seen
|
||||
}
|
||||
if _, exists := seen[index]; exists {
|
||||
return
|
||||
}
|
||||
seen[index] = struct{}{}
|
||||
itemsByUser[userID] = append(itemsByUser[userID], item)
|
||||
}
|
||||
|
||||
func mapKeys(values map[string][]int) []string {
|
||||
keys := make([]string, 0, len(values))
|
||||
for key := range values {
|
||||
key = strings.TrimSpace(key)
|
||||
if key != "" {
|
||||
keys = append(keys, key)
|
||||
}
|
||||
}
|
||||
sort.Strings(keys)
|
||||
return keys
|
||||
}
|
||||
|
||||
func platformMessageContext(ctx context.Context, batch Batch) context.Context {
|
||||
return contexts.Set(ctx, &model.Context{User: &model.Identity{BaseClaims: model.BaseClaims{
|
||||
ID: batch.CreatedBy,
|
||||
DeptId: batch.DeptID,
|
||||
TenantId: strings.TrimSpace(batch.TenantID),
|
||||
}}})
|
||||
}
|
||||
|
||||
func platformMessageParam(batch Batch, group platformRecipientGroup) *model.TMessageLogEditParam {
|
||||
messageType := uint(messageTypeSystem)
|
||||
sendUserType := uint(group.SendUserType)
|
||||
title := platformTitle(batch)
|
||||
content := platformContent(batch)
|
||||
link := platformLink(batch)
|
||||
isRecall := uint(0)
|
||||
|
||||
return &model.TMessageLogEditParam{
|
||||
MessageType: &messageType,
|
||||
SendUserType: &sendUserType,
|
||||
UserIds: gjson.New(group.UserIDs),
|
||||
MessageTitle: &title,
|
||||
MessageContent: &content,
|
||||
MessageLink: &link,
|
||||
IsRecall: &isRecall,
|
||||
}
|
||||
}
|
||||
|
||||
func platformTitle(batch Batch) string {
|
||||
title := strings.TrimSpace(batch.PlatformTitle)
|
||||
if title == "" {
|
||||
return defaultPlatformTitle
|
||||
}
|
||||
return title
|
||||
}
|
||||
|
||||
func platformContent(batch Batch) string {
|
||||
content := strings.TrimSpace(batch.PlatformContent)
|
||||
if content == "" {
|
||||
return defaultPlatformContent
|
||||
}
|
||||
return content
|
||||
}
|
||||
|
||||
func platformLink(batch Batch) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func appendUniqueInt64(values []int64, seen map[int64]struct{}, value int64) []int64 {
|
||||
if value <= 0 {
|
||||
return values
|
||||
}
|
||||
if _, ok := seen[value]; ok {
|
||||
return values
|
||||
}
|
||||
seen[value] = struct{}{}
|
||||
return append(values, value)
|
||||
}
|
||||
Reference in New Issue
Block a user