59eb34976a
iotlcm-admin-svr:管理后台服务。 - Go module:iotlcm → git.5iot.com/iotlcm-public/iotlcm-admin-svr(729 文件) - 凭据与地址脱敏:JWT signingKey(含代码里的 MustGet 默认值)、 MySQL DSN、Redis 口令、告警邮件发件人邮箱全部改为占位; 私网 IP → 文档地址段;库名 xiujie_admin → iotlcm - 真实手机号/邮箱 → 合法 11 位编造号 / example.com - 移除内部资产:CI 触发器、过时 DDL(sql/db_iotlcm.sql)、 私有依赖 go get 行、明文 registry 登录口令 - 启动 banner 统一 IOTLCM 方块字 + 社区惯例署名 - Dockerfile 改用公共基础镜像 - 拼错的 RADEME.md → README.md,README 重写 - 需要真实数据库的用例改为可用 IOTLCM_TEST_WITH_DB=1 显式启用 - 补 Apache-2.0 LICENSE,LF 行尾 + .gitattributes 数据库 schema 不随本仓发布(生产 DDL 已过时),README 已说明。
259 lines
7.5 KiB
Go
259 lines
7.5 KiB
Go
package iot
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strings"
|
|
|
|
"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"
|
|
|
|
"github.com/gogf/gf/v2/database/gdb"
|
|
"github.com/gogf/gf/v2/errors/gerror"
|
|
"github.com/gogf/gf/v2/frame/g"
|
|
)
|
|
|
|
const cardChannelAssocTable = "card_channel_assoc"
|
|
|
|
type cardChannelAssocRecord struct {
|
|
Id int64 `orm:"id"`
|
|
ChannelKey string `orm:"channel_id"`
|
|
MatchType int `orm:"match_type"`
|
|
Iccid string `orm:"iccid"`
|
|
IccidStart string `orm:"iccid_start"`
|
|
IccidEnd string `orm:"iccid_end"`
|
|
Status int `orm:"status"`
|
|
}
|
|
|
|
type cardChannelDisplayRecord struct {
|
|
ChanKey string
|
|
ChanName string
|
|
ChanAlias string
|
|
TempKey string
|
|
}
|
|
|
|
type cardChannelLookupRecord struct {
|
|
Id int64 `orm:"id"`
|
|
ChanKey string `orm:"chan_key"`
|
|
ChanName string `orm:"chan_name"`
|
|
ChanAlias string `orm:"chan_alias"`
|
|
TempKey string `orm:"temp_key"`
|
|
}
|
|
|
|
func applyCardChannelAssocFilter(mod *gdb.Model, cardInfoTable string, chanKey string) *gdb.Model {
|
|
if mod == nil {
|
|
return mod
|
|
}
|
|
chanKey = strings.TrimSpace(chanKey)
|
|
if chanKey == "" {
|
|
return mod
|
|
}
|
|
return mod.Where(cardChannelAssocExistsSQL(cardInfoTable), chanKey)
|
|
}
|
|
|
|
func cardChannelAssocExistsSQL(cardInfoTable string) string {
|
|
cardInfoTable = strings.TrimSpace(cardInfoTable)
|
|
if cardInfoTable == "" {
|
|
cardInfoTable = dao.TSimCardInfo.Table()
|
|
}
|
|
channelTable := dao.TSimChannels.Table()
|
|
cardColumns := dao.TSimCardInfo.Columns()
|
|
channelColumns := dao.TSimChannels.Columns()
|
|
return fmt.Sprintf(
|
|
"EXISTS (SELECT 1 FROM `%s` a LEFT JOIN `%s` c ON c.`%s` = a.`channel_id` WHERE a.`status` = 1 AND c.`%s` = `%s`.`%s` AND c.`%s` = ? AND ((a.`match_type` = 1 AND a.`iccid` COLLATE utf8mb4_general_ci = `%s`.`%s`) OR (a.`match_type` = 2 AND a.`iccid_start` COLLATE utf8mb4_general_ci <= `%s`.`%s` AND a.`iccid_end` COLLATE utf8mb4_general_ci >= `%s`.`%s`)))",
|
|
cardChannelAssocTable,
|
|
channelTable,
|
|
channelColumns.ChanKey,
|
|
channelColumns.TenantId,
|
|
cardInfoTable,
|
|
cardColumns.TenantId,
|
|
channelColumns.ChanKey,
|
|
cardInfoTable,
|
|
cardColumns.Iccid,
|
|
cardInfoTable,
|
|
cardColumns.Iccid,
|
|
cardInfoTable,
|
|
cardColumns.Iccid,
|
|
)
|
|
}
|
|
|
|
func enrichCardChannelList(ctx context.Context, list []*model.TSimCardInfoListModel) error {
|
|
if len(list) == 0 {
|
|
return nil
|
|
}
|
|
channelCache := make(map[string]cardChannelDisplayRecord)
|
|
for _, item := range list {
|
|
if item == nil {
|
|
continue
|
|
}
|
|
display, ok, err := resolveCardChannelDisplayByIccid(ctx, item.Iccid, channelCache)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if !ok {
|
|
continue
|
|
}
|
|
item.ChanKey = display.ChanKey
|
|
item.ChanName = display.ChanName
|
|
item.ChanAlias = display.ChanAlias
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func enrichCardChannelView(ctx context.Context, item *model.TSimCardInfoViewModel) error {
|
|
if item == nil {
|
|
return nil
|
|
}
|
|
display, ok, err := resolveCardChannelDisplayByIccid(ctx, item.Iccid, nil)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if !ok {
|
|
return nil
|
|
}
|
|
item.ChanKey = display.ChanKey
|
|
item.ChanName = display.ChanName
|
|
item.ChanAlias = display.ChanAlias
|
|
return nil
|
|
}
|
|
|
|
func enrichSimKeyChannelFromAssoc(ctx context.Context, simKey *model.SimKey) error {
|
|
if simKey == nil {
|
|
return nil
|
|
}
|
|
display, ok, err := resolveCardChannelDisplayByIccid(ctx, simKey.ICCID, nil)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if ok && strings.TrimSpace(display.ChanKey) != "" {
|
|
simKey.ChanKey = display.ChanKey
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func resolveCardChannelDisplayByIccid(ctx context.Context, iccid string, channelCache map[string]cardChannelDisplayRecord) (cardChannelDisplayRecord, bool, error) {
|
|
assoc, err := resolveCardChannelAssocByIccid(ctx, iccid)
|
|
if err != nil || assoc == nil {
|
|
return cardChannelDisplayRecord{}, false, err
|
|
}
|
|
return resolveCardChannelDisplayByAssoc(ctx, assoc, channelCache)
|
|
}
|
|
|
|
func resolveCardChannelDisplayByAssoc(ctx context.Context, assoc *cardChannelAssocRecord, channelCache map[string]cardChannelDisplayRecord) (cardChannelDisplayRecord, bool, error) {
|
|
if assoc == nil {
|
|
return cardChannelDisplayRecord{}, false, nil
|
|
}
|
|
return resolveCardChannelDisplayByChannelKey(ctx, assoc.ChannelKey, channelCache)
|
|
}
|
|
|
|
func resolveCardChannelAssocByIccid(ctx context.Context, iccid string) (*cardChannelAssocRecord, error) {
|
|
iccid = strings.TrimSpace(iccid)
|
|
if iccid == "" {
|
|
return nil, nil
|
|
}
|
|
|
|
var exact *cardChannelAssocRecord
|
|
if err := g.DB().Ctx(ctx).Model(cardChannelAssocTable).
|
|
Fields("id", "channel_id", "match_type", "iccid", "iccid_start", "iccid_end", "status").
|
|
Where("status", 1).
|
|
Where("match_type", 1).
|
|
Where("iccid COLLATE utf8mb4_general_ci = ?", iccid).
|
|
OrderDesc("id").
|
|
Limit(1).
|
|
Scan(&exact); err != nil {
|
|
return nil, gerror.Wrap(err, "查询卡通道单卡关联失败")
|
|
}
|
|
if exact != nil && strings.TrimSpace(exact.ChannelKey) != "" {
|
|
return exact, nil
|
|
}
|
|
|
|
var ranged *cardChannelAssocRecord
|
|
if err := g.DB().Ctx(ctx).Model(cardChannelAssocTable).
|
|
Fields("id", "channel_id", "match_type", "iccid", "iccid_start", "iccid_end", "status").
|
|
Where("status", 1).
|
|
Where("match_type", 2).
|
|
Where("iccid_start COLLATE utf8mb4_general_ci <= ? AND iccid_end COLLATE utf8mb4_general_ci >= ?", iccid, iccid).
|
|
OrderDesc("id").
|
|
Limit(1).
|
|
Scan(&ranged); err != nil {
|
|
return nil, gerror.Wrap(err, "查询卡通道号段关联失败")
|
|
}
|
|
if ranged != nil && strings.TrimSpace(ranged.ChannelKey) != "" {
|
|
return ranged, nil
|
|
}
|
|
return nil, nil
|
|
}
|
|
|
|
func resolveCardChannelDisplayByChannelKey(ctx context.Context, chanKey string, channelCache map[string]cardChannelDisplayRecord) (cardChannelDisplayRecord, bool, error) {
|
|
chanKey = strings.TrimSpace(chanKey)
|
|
if chanKey == "" {
|
|
return cardChannelDisplayRecord{}, false, nil
|
|
}
|
|
if channelCache != nil {
|
|
if cached, ok := channelCache[chanKey]; ok {
|
|
return cached, true, nil
|
|
}
|
|
}
|
|
|
|
channel, err := loadCardChannelByKey(ctx, chanKey)
|
|
if err != nil {
|
|
return cardChannelDisplayRecord{}, false, err
|
|
}
|
|
if channel == nil {
|
|
return cardChannelDisplayRecord{}, false, nil
|
|
}
|
|
|
|
display := cardChannelDisplayRecord{
|
|
ChanKey: strings.TrimSpace(channel.ChanKey),
|
|
ChanName: strings.TrimSpace(channel.ChanName),
|
|
ChanAlias: strings.TrimSpace(channel.ChanAlias),
|
|
TempKey: strings.TrimSpace(channel.TempKey),
|
|
}
|
|
if channelCache != nil {
|
|
channelCache[chanKey] = display
|
|
}
|
|
return display, true, nil
|
|
}
|
|
|
|
func loadCardChannelByKey(ctx context.Context, chanKey string) (*cardChannelLookupRecord, error) {
|
|
chanKey = strings.TrimSpace(chanKey)
|
|
if chanKey == "" {
|
|
return nil, nil
|
|
}
|
|
var channel *cardChannelLookupRecord
|
|
columns := dao.TSimChannels.Columns()
|
|
if err := cardChannelLookupModel(ctx).
|
|
Where(columns.ChanKey, chanKey).
|
|
Limit(1).
|
|
Scan(&channel); err != nil {
|
|
return nil, gerror.Wrap(err, "查询通道信息失败")
|
|
}
|
|
if channel != nil && strings.TrimSpace(channel.ChanKey) != "" {
|
|
return channel, nil
|
|
}
|
|
|
|
channel = nil
|
|
if err := dao.TSimChannels.Ctx(ctx).
|
|
Fields(columns.Id, columns.ChanKey, columns.ChanName, columns.ChanAlias, columns.TempKey).
|
|
Where(columns.ChanKey, chanKey).
|
|
Limit(1).
|
|
Scan(&channel); err != nil {
|
|
return nil, gerror.Wrap(err, "查询通道信息失败")
|
|
}
|
|
return channel, nil
|
|
}
|
|
|
|
func cardChannelLookupModel(ctx context.Context) *gdb.Model {
|
|
columns := dao.TSimChannels.Columns()
|
|
return dao.TSimChannels.Ctx(ctx).
|
|
Fields(columns.Id, columns.ChanKey, columns.ChanName, columns.ChanAlias, columns.TempKey).
|
|
Where(columns.TenantId, contexts.GetTenantId(ctx))
|
|
}
|
|
|
|
func logCardChannelDisplayResolverError(ctx context.Context, err error) {
|
|
if err != nil {
|
|
g.Log().Warningf(ctx, "load card channel display failed: %v", err)
|
|
}
|
|
}
|