feat: support ims user, voip auth data and backup UE data
This commit is contained in:
486
features/ue/ims_user/controller.go
Normal file
486
features/ue/ims_user/controller.go
Normal file
@@ -0,0 +1,486 @@
|
||||
package ims_user
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"be.ems/src/framework/constants/uploadsubpath"
|
||||
"be.ems/src/framework/i18n"
|
||||
"be.ems/src/framework/telnet"
|
||||
"be.ems/src/framework/utils/ctx"
|
||||
"be.ems/src/framework/utils/file"
|
||||
"be.ems/src/framework/utils/parse"
|
||||
"be.ems/src/framework/vo/result"
|
||||
neService "be.ems/src/modules/network_element/service"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/gin-gonic/gin/binding"
|
||||
)
|
||||
|
||||
// 实例化控制层 Controller 结构体
|
||||
var NewController = &Controller{
|
||||
volteUserService: NewVoLTEService,
|
||||
neInfoService: neService.NewNeInfo,
|
||||
}
|
||||
|
||||
// IMS用户信息 控制层处理
|
||||
//
|
||||
// @Description IMS用户信息 控制层处理
|
||||
type Controller struct {
|
||||
volteUserService *Service // IMS User信息服务
|
||||
neInfoService *neService.NeInfo // 网元信息服务
|
||||
}
|
||||
|
||||
func (s *Controller) ResetData(c *gin.Context) {
|
||||
language := ctx.AcceptLanguage(c)
|
||||
neId := c.Param("neId")
|
||||
if neId == "" {
|
||||
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
|
||||
return
|
||||
}
|
||||
|
||||
data := s.volteUserService.ResetData(neId)
|
||||
c.JSON(200, result.OkData(data))
|
||||
}
|
||||
|
||||
|
||||
func (s *Controller) List(c *gin.Context) {
|
||||
querys := ctx.QueryMap(c)
|
||||
// querys["userName"] = ctx.LoginUserToUserName(c)
|
||||
// 判断租户角色
|
||||
loginUser, _ := ctx.LoginUser(c)
|
||||
if len(loginUser.User.Roles) > 0 {
|
||||
for _, v := range loginUser.User.Roles {
|
||||
if v.RoleKey == "tenant" {
|
||||
querys["tenantName"] = loginUser.User.UserName
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
data := s.volteUserService.SelectPage(querys)
|
||||
c.JSON(200, result.Ok(data))
|
||||
}
|
||||
|
||||
func (s *Controller) Info(c *gin.Context) {
|
||||
language := ctx.AcceptLanguage(c)
|
||||
neId := c.Param("neId")
|
||||
imsi := c.Param("imsi")
|
||||
if neId == "" || imsi == "" {
|
||||
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
|
||||
return
|
||||
}
|
||||
|
||||
// 查询网元获取IP
|
||||
neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID("UDM", neId)
|
||||
if neInfo.NeId != neId || neInfo.IP == "" {
|
||||
c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
|
||||
return
|
||||
}
|
||||
// 网元主机的Telnet客户端
|
||||
telnetClient, err := s.neInfoService.NeRunTelnetClient("UDM", neId, 1)
|
||||
if err != nil {
|
||||
c.JSON(200, result.ErrMsg(err.Error()))
|
||||
return
|
||||
}
|
||||
defer telnetClient.Close()
|
||||
|
||||
// 发送MML
|
||||
cmd := fmt.Sprintf("dsp imsuser:imsi=%s", imsi)
|
||||
data, err := telnet.ConvertToMap(telnetClient, cmd)
|
||||
if err != nil {
|
||||
c.JSON(200, result.ErrMsg(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
if len(data) == 0 {
|
||||
c.JSON(200, result.ErrMsg("Not found VoLTE user data"))
|
||||
return
|
||||
}
|
||||
|
||||
// 解析返回的数据
|
||||
u := s.volteUserService.ParseInfo(imsi, neId, data)
|
||||
s.volteUserService.Insert(neId, u)
|
||||
c.JSON(200, result.OkData(u))
|
||||
}
|
||||
|
||||
func (s *Controller) Add(c *gin.Context) {
|
||||
language := ctx.AcceptLanguage(c)
|
||||
neId := c.Param("neId")
|
||||
if neId == "" {
|
||||
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
|
||||
return
|
||||
}
|
||||
|
||||
var body VoLTEUser
|
||||
err := c.ShouldBindBodyWith(&body, binding.JSON)
|
||||
if err != nil || len(body.IMSI) < IMSI_MAX_LENGTH {
|
||||
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
|
||||
return
|
||||
}
|
||||
|
||||
// 查询网元获取IP
|
||||
neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID("UDM", neId)
|
||||
if neInfo.NeId != neId || neInfo.IP == "" {
|
||||
c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
|
||||
return
|
||||
}
|
||||
// 网元主机的Telnet客户端
|
||||
telnetClient, err := s.neInfoService.NeRunTelnetClient("UDM", neId, 1)
|
||||
if err != nil {
|
||||
c.JSON(200, result.ErrMsg(err.Error()))
|
||||
return
|
||||
}
|
||||
defer telnetClient.Close()
|
||||
|
||||
// 发送MML
|
||||
cmd := fmt.Sprintf("add imsuser:imsi=%s,", body.IMSI)
|
||||
cmd += s.volteUserService.ParseCommandParams(body)
|
||||
data, err := telnet.ConvertToStr(telnetClient, cmd)
|
||||
if err != nil {
|
||||
c.JSON(200, result.ErrMsg(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
// 命令ok时
|
||||
if strings.Contains(data, "ok") {
|
||||
body.NeId = neId
|
||||
s.volteUserService.Insert(neId, body)
|
||||
}
|
||||
c.JSON(200, result.OkData(data))
|
||||
}
|
||||
|
||||
func (s *Controller) Adds(c *gin.Context) {
|
||||
language := ctx.AcceptLanguage(c)
|
||||
neId := c.Param("neId")
|
||||
num := c.Param("num")
|
||||
if neId == "" || num == "" {
|
||||
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
|
||||
return
|
||||
}
|
||||
|
||||
var body VoLTEUser
|
||||
err := c.ShouldBindBodyWith(&body, binding.JSON)
|
||||
if err != nil || len(body.IMSI) < IMSI_MAX_LENGTH {
|
||||
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
|
||||
return
|
||||
}
|
||||
|
||||
// 查询网元获取IP
|
||||
neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID("UDM", neId)
|
||||
if neInfo.NeId != neId || neInfo.IP == "" {
|
||||
c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
|
||||
return
|
||||
}
|
||||
// 网元主机的Telnet客户端
|
||||
telnetClient, err := s.neInfoService.NeRunTelnetClient("UDM", neId, 1)
|
||||
if err != nil {
|
||||
c.JSON(200, result.ErrMsg(err.Error()))
|
||||
return
|
||||
}
|
||||
defer telnetClient.Close()
|
||||
|
||||
// 发送MML
|
||||
cmd := fmt.Sprintf("baa imsuser:start_imsi=%s,start_msisdn=%s,sub_num=%s,", body.IMSI, body.MSISDN, num)
|
||||
cmd += s.volteUserService.ParseCommandParams(body)
|
||||
// 去除msisdn参数,避免重复
|
||||
omemsisdn := fmt.Sprintf(",msisdn=%s,", body.MSISDN)
|
||||
cmd = strings.Replace(cmd, omemsisdn, ",", 1)
|
||||
data, err := telnet.ConvertToStr(telnetClient, cmd)
|
||||
if err != nil {
|
||||
c.JSON(200, result.ErrMsg(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(200, result.OkData(data))
|
||||
}
|
||||
|
||||
func (s *Controller) Edit(c *gin.Context) {
|
||||
language := ctx.AcceptLanguage(c)
|
||||
neId := c.Param("neId")
|
||||
if neId == "" {
|
||||
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
|
||||
return
|
||||
}
|
||||
|
||||
var body VoLTEUser
|
||||
err := c.ShouldBindBodyWith(&body, binding.JSON)
|
||||
if err != nil || len(body.IMSI) < IMSI_MAX_LENGTH {
|
||||
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
|
||||
return
|
||||
}
|
||||
|
||||
// 查询网元获取IP
|
||||
neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID("UDM", neId)
|
||||
if neInfo.NeId != neId || neInfo.IP == "" {
|
||||
c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
|
||||
return
|
||||
}
|
||||
// 网元主机的Telnet客户端
|
||||
telnetClient, err := s.neInfoService.NeRunTelnetClient("UDM", neId, 1)
|
||||
if err != nil {
|
||||
c.JSON(200, result.ErrMsg(err.Error()))
|
||||
return
|
||||
}
|
||||
defer telnetClient.Close()
|
||||
|
||||
// 发送MML
|
||||
cmd := fmt.Sprintf("mod imsuser:imsi=%s,", body.IMSI)
|
||||
cmd += s.volteUserService.ParseCommandParams(body)
|
||||
data, err := telnet.ConvertToStr(telnetClient, cmd)
|
||||
if err != nil {
|
||||
c.JSON(200, result.ErrMsg(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
// 命令ok时
|
||||
if strings.Contains(data, "ok") {
|
||||
body.NeId = neId
|
||||
s.volteUserService.Insert(neId, body)
|
||||
}
|
||||
c.JSON(200, result.OkData(data))
|
||||
}
|
||||
|
||||
func (s *Controller) Remove(c *gin.Context) {
|
||||
language := ctx.AcceptLanguage(c)
|
||||
neId := c.Param("neId")
|
||||
imsi := c.Param("imsi")
|
||||
if neId == "" || len(imsi) < IMSI_MAX_LENGTH {
|
||||
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
|
||||
return
|
||||
}
|
||||
|
||||
// 处理字符转id数组后去重
|
||||
imsiArr := strings.Split(imsi, ",")
|
||||
uniqueIDs := parse.RemoveDuplicates(imsiArr)
|
||||
if len(uniqueIDs) <= 0 {
|
||||
c.JSON(200, result.Err(nil))
|
||||
return
|
||||
}
|
||||
|
||||
// 查询网元获取IP
|
||||
neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID("UDM", neId)
|
||||
if neInfo.NeId != neId || neInfo.IP == "" {
|
||||
c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
|
||||
return
|
||||
}
|
||||
// 网元主机的Telnet客户端
|
||||
telnetClient, err := s.neInfoService.NeRunTelnetClient("UDM", neId, 1)
|
||||
if err != nil {
|
||||
c.JSON(200, result.ErrMsg(err.Error()))
|
||||
return
|
||||
}
|
||||
defer telnetClient.Close()
|
||||
|
||||
resultData := map[string]string{}
|
||||
for _, imsi := range uniqueIDs {
|
||||
// 发送MML
|
||||
cmd := fmt.Sprintf("del imsuser:imsi=%s", imsi)
|
||||
data, err := telnet.ConvertToStr(telnetClient, cmd)
|
||||
if err != nil {
|
||||
resultData[imsi] = err.Error()
|
||||
continue
|
||||
}
|
||||
// 命令ok时
|
||||
if strings.Contains(data, "ok") {
|
||||
s.volteUserService.Delete(neId, imsi)
|
||||
}
|
||||
resultData[imsi] = data
|
||||
}
|
||||
|
||||
c.JSON(200, result.OkData(resultData))
|
||||
}
|
||||
|
||||
func (s *Controller) Removes(c *gin.Context) {
|
||||
language := ctx.AcceptLanguage(c)
|
||||
neId := c.Param("neId")
|
||||
imsi := c.Param("imsi")
|
||||
num := c.Param("num")
|
||||
if neId == "" || len(imsi) < IMSI_MAX_LENGTH || num == "" {
|
||||
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
|
||||
return
|
||||
}
|
||||
|
||||
// 查询网元获取IP
|
||||
neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID("UDM", neId)
|
||||
if neInfo.NeId != neId || neInfo.IP == "" {
|
||||
c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
|
||||
return
|
||||
}
|
||||
// 网元主机的Telnet客户端
|
||||
telnetClient, err := s.neInfoService.NeRunTelnetClient("UDM", neId, 1)
|
||||
if err != nil {
|
||||
c.JSON(200, result.ErrMsg(err.Error()))
|
||||
return
|
||||
}
|
||||
defer telnetClient.Close()
|
||||
|
||||
// 发送MML
|
||||
cmd := fmt.Sprintf("bde imsuser:start_imsi=%s,sub_num=%s", imsi, num)
|
||||
data, err := telnet.ConvertToStr(telnetClient, cmd)
|
||||
if err != nil {
|
||||
c.JSON(200, result.ErrMsg(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
// 命令ok时
|
||||
if strings.Contains(data, "ok") {
|
||||
s.volteUserService.LoadData(neId, imsi, num)
|
||||
}
|
||||
c.JSON(200, result.OkData(data))
|
||||
}
|
||||
|
||||
func (s *Controller) Export(c *gin.Context) {
|
||||
language := ctx.AcceptLanguage(c)
|
||||
// 查询结果,根据查询条件结果,单页最大值限制
|
||||
querys := ctx.BodyJSONMap(c)
|
||||
neId := querys["neId"].(string)
|
||||
fileType := querys["type"].(string)
|
||||
if neId == "" || fileType == "" {
|
||||
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
|
||||
return
|
||||
}
|
||||
if !(fileType == "csv" || fileType == "txt") {
|
||||
c.JSON(200, result.ErrMsg(i18n.TKey(language, "ne.udm.errImportUserSubFileFormat")))
|
||||
return
|
||||
}
|
||||
|
||||
// 判断租户角色
|
||||
loginUser, _ := ctx.LoginUser(c)
|
||||
if len(loginUser.User.Roles) > 0 {
|
||||
for _, v := range loginUser.User.Roles {
|
||||
if v.RoleKey == "tenant" {
|
||||
querys["tenantName"] = loginUser.User.UserName
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
querys["pageNum"] = 1
|
||||
querys["pageSize"] = 10000
|
||||
data := s.volteUserService.SelectPage(querys)
|
||||
if parse.Number(data["total"]) == 0 {
|
||||
// 导出数据记录为空
|
||||
c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.exportEmpty")))
|
||||
return
|
||||
}
|
||||
rows := data["rows"].([]VoLTEUser)
|
||||
|
||||
// rows := s.volteUserService.SelectList(VoLTEUser{NeId: neId})
|
||||
if len(rows) <= 0 {
|
||||
// 导出数据记录为空
|
||||
c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.exportEmpty")))
|
||||
return
|
||||
}
|
||||
|
||||
// 文件名
|
||||
fileName := fmt.Sprintf("udm_volte_user_export_%s_%d.%s", neId, time.Now().UnixMilli(), fileType)
|
||||
filePath := filepath.Join(file.ParseUploadFileDir(uploadsubpath.EXPORT), fileName)
|
||||
|
||||
if fileType == "csv" {
|
||||
// 转换数据
|
||||
data := [][]string{}
|
||||
data = append(data, []string{"IMSI", "MSISDN", "VoLTE", "VNI"})
|
||||
for _, v := range rows {
|
||||
data = append(data, []string{v.IMSI, v.MSISDN, v.VoLTE, v.VNI})
|
||||
}
|
||||
// 输出到文件
|
||||
if err := file.WriterFileCSV(data, filePath); err != nil {
|
||||
c.JSON(200, result.ErrMsg(err.Error()))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if fileType == "txt" {
|
||||
// 转换数据
|
||||
data := [][]string{}
|
||||
for _, v := range rows {
|
||||
data = append(data, []string{v.IMSI, v.MSISDN, v.VoLTE, v.VNI})
|
||||
}
|
||||
// 输出到文件
|
||||
if err := file.WriterFileTXT(data, ",", filePath); err != nil {
|
||||
c.JSON(200, result.ErrMsg(err.Error()))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
c.FileAttachment(filePath, fileName)
|
||||
}
|
||||
|
||||
func (s *Controller) Import(c *gin.Context) {
|
||||
language := ctx.AcceptLanguage(c)
|
||||
var body struct {
|
||||
NeId string `json:"neId" binding:"required"`
|
||||
UploadPath string `json:"uploadPath" binding:"required"`
|
||||
}
|
||||
if err := c.ShouldBindBodyWith(&body, binding.JSON); err != nil {
|
||||
c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
|
||||
return
|
||||
}
|
||||
|
||||
// 判断文件名
|
||||
if !(strings.HasSuffix(body.UploadPath, ".csv") || strings.HasSuffix(body.UploadPath, ".txt")) {
|
||||
c.JSON(200, result.ErrMsg(i18n.TKey(language, "ne.udm.errImportUserSubFileFormat")))
|
||||
return
|
||||
}
|
||||
|
||||
// 查询网元获取IP
|
||||
neInfo := s.neInfoService.SelectNeInfoByNeTypeAndNeID("UDM", body.NeId)
|
||||
if neInfo.NeId != body.NeId || neInfo.IP == "" {
|
||||
c.JSON(200, result.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
|
||||
return
|
||||
}
|
||||
|
||||
// 网元主机的SSH客户端
|
||||
sshClient, err := s.neInfoService.NeRunSSHClient(neInfo.NeType, neInfo.NeId)
|
||||
if err != nil {
|
||||
c.JSON(200, result.ErrMsg(err.Error()))
|
||||
return
|
||||
}
|
||||
defer sshClient.Close()
|
||||
// 网元主机的SSH客户端进行文件传输
|
||||
sftpClient, err := sshClient.NewClientSFTP()
|
||||
if err != nil {
|
||||
c.JSON(200, result.ErrMsg(err.Error()))
|
||||
return
|
||||
}
|
||||
defer sftpClient.Close()
|
||||
|
||||
// 本地文件
|
||||
localFilePath := file.ParseUploadFilePath(body.UploadPath)
|
||||
neFilePath := fmt.Sprintf("/tmp/%s", filepath.Base(localFilePath))
|
||||
// 复制到远程
|
||||
if err = sftpClient.CopyFileLocalToRemote(localFilePath, neFilePath); err != nil {
|
||||
c.JSON(200, result.ErrMsg("error uploading file"))
|
||||
return
|
||||
}
|
||||
|
||||
// 网元主机的Telnet客户端
|
||||
telnetClient, err := s.neInfoService.NeRunTelnetClient(neInfo.NeType, neInfo.NeId, 1)
|
||||
if err != nil {
|
||||
c.JSON(200, result.ErrMsg(err.Error()))
|
||||
return
|
||||
}
|
||||
defer telnetClient.Close()
|
||||
|
||||
// 发送MML
|
||||
cmd := fmt.Sprintf("import imsuser:path=%s", neFilePath)
|
||||
data, err := telnet.ConvertToStr(telnetClient, cmd)
|
||||
if err != nil {
|
||||
c.JSON(200, result.ErrMsg(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
// 命令ok时
|
||||
if strings.Contains(data, "ok") {
|
||||
if strings.HasSuffix(body.UploadPath, ".csv") {
|
||||
data := file.ReadFileCSV(localFilePath)
|
||||
go s.volteUserService.InsertData(neInfo.NeId, "csv", data)
|
||||
}
|
||||
if strings.HasSuffix(body.UploadPath, ".txt") {
|
||||
data := file.ReadFileTXT(",", localFilePath)
|
||||
go s.volteUserService.InsertData(neInfo.NeId, "txt", data)
|
||||
}
|
||||
}
|
||||
c.JSON(200, result.OkMsg(data))
|
||||
}
|
||||
26
features/ue/ims_user/model.go
Normal file
26
features/ue/ims_user/model.go
Normal file
@@ -0,0 +1,26 @@
|
||||
package ims_user
|
||||
|
||||
const (
|
||||
// IMSI 号码长度
|
||||
IMSI_MAX_LENGTH = 15
|
||||
// MSISDN 号码长度
|
||||
MSISDN_MAX_LENGTH = 15
|
||||
)
|
||||
|
||||
// @Description VoLTE用户信息
|
||||
type VoLTEUser struct {
|
||||
ID string `json:"id" gorm:"column:id;primaryKey;autoIncrement"` // 主键
|
||||
NeId string `json:"neId" gorm:"column:ne_id"` // UDM网元标识
|
||||
IMSI string `json:"imsi" gorm:"column:imsi"` // SIM卡/USIM卡ID
|
||||
MSISDN string `json:"msisdn" gorm:"column:msisdn"` // 用户电话号码
|
||||
VoLTE string `json:"volte" gorm:"column:volte"` // VoLTE
|
||||
VNI string `json:"vni" gorm:"column:vni"` // VNI
|
||||
|
||||
TenantID string `json:"tenantID" gorm:"column:tenant_id"`
|
||||
TenantName string `json:"tenantName" gorm:"-"`
|
||||
}
|
||||
|
||||
// TableName 表名称
|
||||
func (*VoLTEUser) TableName() string {
|
||||
return "u_ims_user"
|
||||
}
|
||||
272
features/ue/ims_user/repository.go
Normal file
272
features/ue/ims_user/repository.go
Normal file
@@ -0,0 +1,272 @@
|
||||
package ims_user
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
dborm "be.ems/lib/core/datasource"
|
||||
"be.ems/lib/log"
|
||||
"be.ems/src/framework/datasource"
|
||||
"be.ems/src/framework/logger"
|
||||
"be.ems/src/framework/utils/parse"
|
||||
"be.ems/src/framework/utils/repo"
|
||||
)
|
||||
|
||||
// 实例化数据层 Repository 结构体
|
||||
var NewVoLTERepository = &Repository{
|
||||
selectSql: `select
|
||||
s.id, s.ne_id, s.imsi, s.msisdn, s.volte, s.vni,
|
||||
t.tenant_id, t.tenant_name
|
||||
from u_ims_user s
|
||||
left join sys_tenant t on t.tenant_id = s.tenant_id and t.status = 1`,
|
||||
|
||||
resultMap: map[string]string{
|
||||
"id": "ID",
|
||||
"ne_id": "NeId",
|
||||
"imsi": "IMSI",
|
||||
"msisdn": "MSISDN",
|
||||
"volte": "VoLTE",
|
||||
"vni": "VNI",
|
||||
|
||||
"tenant_id": "TenantID",
|
||||
"tenant_name": "TenantName", // Tenant name for multi-tenancy
|
||||
},
|
||||
}
|
||||
|
||||
// Repository UDM签约信息表 数据层处理
|
||||
type Repository struct {
|
||||
// 查询视图对象SQL
|
||||
selectSql string
|
||||
// 结果字段与实体映射
|
||||
resultMap map[string]string
|
||||
}
|
||||
|
||||
// convertResultRows 将结果记录转实体结果组
|
||||
func (r *Repository) convertResultRows(rows []map[string]any) []VoLTEUser {
|
||||
arr := make([]VoLTEUser, 0)
|
||||
for _, row := range rows {
|
||||
item := VoLTEUser{}
|
||||
for key, value := range row {
|
||||
if keyMapper, ok := r.resultMap[key]; ok {
|
||||
repo.SetFieldValue(&item, keyMapper, value)
|
||||
}
|
||||
}
|
||||
arr = append(arr, item)
|
||||
}
|
||||
return arr
|
||||
}
|
||||
|
||||
// ClearAndInsert 清空ne_id后新增实体
|
||||
func (r *Repository) ClearAndInsert(neId string, u []VoLTEUser) int64 {
|
||||
// 不指定neID时,用 TRUNCATE 清空表快
|
||||
// _, err := datasource.ExecDB("", "TRUNCATE TABLE u_ims_user", nil)
|
||||
_, err := datasource.ExecDB("", "DELETE FROM u_ims_user WHERE ne_id = ?", []any{neId})
|
||||
if err != nil {
|
||||
logger.Errorf("TRUNCATE err => %v", err)
|
||||
}
|
||||
|
||||
return r.Inserts(u)
|
||||
}
|
||||
|
||||
// SelectPage 根据条件分页查询字典类型
|
||||
func (r *Repository) SelectPage(query map[string]any) map[string]any {
|
||||
// 查询条件拼接
|
||||
var conditions []string
|
||||
var params []any
|
||||
if v, ok := query["imsi"]; ok && v != "" {
|
||||
conditions = append(conditions, "imsi like concat(concat('%', ?), '%')")
|
||||
params = append(params, strings.Trim(v.(string), " "))
|
||||
}
|
||||
if v, ok := query["msisdn"]; ok && v != "" {
|
||||
conditions = append(conditions, "msisdn like concat(concat('%', ?), '%')")
|
||||
params = append(params, strings.Trim(v.(string), " "))
|
||||
}
|
||||
if v, ok := query["imsis"]; ok && v != "" {
|
||||
placeholder := repo.KeyPlaceholderByQuery(len(v.([]any)))
|
||||
conditions = append(conditions, fmt.Sprintf("imsi in (%s)", placeholder))
|
||||
for _, v := range v.([]any) {
|
||||
params = append(params, v.(string))
|
||||
}
|
||||
}
|
||||
|
||||
// for multi-tenancy solution
|
||||
if v, ok := query["tenantName"]; ok && v != "" {
|
||||
var tenantID []string
|
||||
err := dborm.DefaultDB().Table("sys_tenant").
|
||||
Where("tenant_name=? and status=1", v).Cols("tenant_id").Distinct().Find(&tenantID)
|
||||
if err != nil {
|
||||
log.Errorf("Find tenant_id from sys_user err => %v", err)
|
||||
}
|
||||
log.Tracef("userName=%v, tenantID=%v", v, tenantID)
|
||||
if len(tenantID) > 0 {
|
||||
conditions = append(conditions, "s.tenant_id = ?")
|
||||
params = append(params, tenantID[0])
|
||||
}
|
||||
} else if v, ok := query["userName"]; ok && v != "" {
|
||||
var tenantID string
|
||||
_, err := dborm.DefaultDB().Table("sys_user").
|
||||
Where("user_name=?", v).Cols("tenant_id").Distinct().Get(&tenantID)
|
||||
if err != nil {
|
||||
log.Errorf("Find tenant_id from sys_user err => %v", err)
|
||||
}
|
||||
log.Tracef("userName=%v, tenantID=%v", v, tenantID)
|
||||
if tenantID != "" {
|
||||
conditions = append(conditions, "s.tenant_id = ?")
|
||||
params = append(params, tenantID)
|
||||
query["neId"] = ""
|
||||
}
|
||||
}
|
||||
if v, ok := query["neId"]; ok && v != "" {
|
||||
conditions = append(conditions, "ne_id = ?")
|
||||
params = append(params, v)
|
||||
}
|
||||
// 构建查询条件语句
|
||||
whereSql := ""
|
||||
if len(conditions) > 0 {
|
||||
whereSql += " where " + strings.Join(conditions, " and ")
|
||||
}
|
||||
|
||||
result := map[string]any{
|
||||
"total": 0,
|
||||
"rows": []VoLTEUser{},
|
||||
}
|
||||
|
||||
// 查询数量 长度为0直接返回
|
||||
totalSql := "select count(1) as 'total' from u_ims_user s"
|
||||
totalRows, err := datasource.RawDB("", totalSql+whereSql, params)
|
||||
if err != nil {
|
||||
logger.Errorf("total err => %v", err)
|
||||
return result
|
||||
}
|
||||
total := parse.Number(totalRows[0]["total"])
|
||||
if total == 0 {
|
||||
return result
|
||||
} else {
|
||||
result["total"] = total
|
||||
}
|
||||
|
||||
// 分页
|
||||
pageNum, pageSize := repo.PageNumSize(query["pageNum"], query["pageSize"])
|
||||
pageSql := " limit ?,? "
|
||||
params = append(params, pageNum*pageSize)
|
||||
params = append(params, pageSize)
|
||||
|
||||
// 排序
|
||||
orderSql := ""
|
||||
if v, ok := query["sortField"]; ok && v != "" {
|
||||
sortSql := v.(string)
|
||||
if o, ok := query["sortOrder"]; ok && o != nil && v != "" {
|
||||
if o == "desc" {
|
||||
sortSql += " desc "
|
||||
} else {
|
||||
sortSql += " asc "
|
||||
}
|
||||
}
|
||||
orderSql = fmt.Sprintf(" order by %s ", sortSql)
|
||||
}
|
||||
|
||||
// 查询数据
|
||||
querySql := r.selectSql + whereSql + orderSql + pageSql
|
||||
results, err := datasource.RawDB("", querySql, params)
|
||||
if err != nil {
|
||||
logger.Errorf("query err => %v", err)
|
||||
return result
|
||||
}
|
||||
|
||||
// 转换实体
|
||||
result["rows"] = r.convertResultRows(results)
|
||||
return result
|
||||
}
|
||||
|
||||
// SelectList 根据实体查询
|
||||
func (r *Repository) SelectList(u VoLTEUser) []VoLTEUser {
|
||||
// 查询条件拼接
|
||||
var conditions []string
|
||||
var params []any
|
||||
if u.IMSI != "" {
|
||||
conditions = append(conditions, "imsi = ?")
|
||||
params = append(params, u.IMSI)
|
||||
}
|
||||
if u.NeId != "" {
|
||||
conditions = append(conditions, "ne_id = ?")
|
||||
params = append(params, u.NeId)
|
||||
}
|
||||
|
||||
// 构建查询条件语句
|
||||
whereSql := ""
|
||||
if len(conditions) > 0 {
|
||||
whereSql += " where " + strings.Join(conditions, " and ")
|
||||
}
|
||||
|
||||
// 查询数据
|
||||
querySql := r.selectSql + whereSql + " order by imsi asc "
|
||||
results, err := datasource.RawDB("", querySql, params)
|
||||
if err != nil {
|
||||
logger.Errorf("query err => %v", err)
|
||||
}
|
||||
|
||||
// 转换实体
|
||||
return r.convertResultRows(results)
|
||||
}
|
||||
|
||||
// SelectByIMSIAndNeID 通过imsi和ne_id查询
|
||||
func (r *Repository) SelectByIMSIAndNeID(imsi, neId string) VoLTEUser {
|
||||
querySql := r.selectSql + " where imsi = ? and ne_id = ?"
|
||||
results, err := datasource.RawDB("", querySql, []any{imsi, neId})
|
||||
if err != nil {
|
||||
logger.Errorf("query err => %v", err)
|
||||
return VoLTEUser{}
|
||||
}
|
||||
// 转换实体
|
||||
rows := r.convertResultRows(results)
|
||||
if len(rows) > 0 {
|
||||
return rows[0]
|
||||
}
|
||||
return VoLTEUser{}
|
||||
}
|
||||
|
||||
// Insert 批量添加
|
||||
func (r *Repository) Inserts(uArr []VoLTEUser) int64 {
|
||||
// multi-tenancy
|
||||
r.SetTenantID(&uArr)
|
||||
|
||||
tx := datasource.DefaultDB().CreateInBatches(uArr, 2000)
|
||||
if err := tx.Error; err != nil {
|
||||
logger.Errorf("CreateInBatches err => %v", err)
|
||||
}
|
||||
return tx.RowsAffected
|
||||
}
|
||||
|
||||
// Delete 删除实体
|
||||
func (r *Repository) Delete(imsi, neId string) int64 {
|
||||
tx := datasource.DefaultDB().Where("imsi = ? and ne_id = ?", imsi, neId).Delete(&Repository{})
|
||||
if err := tx.Error; err != nil {
|
||||
logger.Errorf("Delete err => %v", err)
|
||||
}
|
||||
return tx.RowsAffected
|
||||
}
|
||||
|
||||
// DeletePrefixByIMSI 删除前缀匹配的实体
|
||||
func (r *Repository) DeletePrefixByIMSI(imsiPrefix, neId string) int64 {
|
||||
tx := datasource.DefaultDB().Where("imsi like concat(?, '%') and ne_id = ?", imsiPrefix, neId).Delete(&Repository{})
|
||||
if err := tx.Error; err != nil {
|
||||
logger.Errorf("DeletePrefixByIMSI err => %v", err)
|
||||
}
|
||||
return tx.RowsAffected
|
||||
}
|
||||
|
||||
func (r *Repository) SetTenantID(subArr *[]VoLTEUser) {
|
||||
for s := 0; s < len(*subArr); s++ {
|
||||
var tenantID []string
|
||||
err := dborm.DefaultDB().Table("sys_tenant").
|
||||
Where("status='1' and tenancy_type='IMSI' and ? like tenancy_key", (*subArr)[s].IMSI).
|
||||
Cols("parent_id").Distinct().Find(&tenantID)
|
||||
if err != nil {
|
||||
logger.Errorf("Find tenant_id err => %v", err)
|
||||
continue
|
||||
}
|
||||
if len(tenantID) > 0 {
|
||||
(*subArr)[s].TenantID = tenantID[0]
|
||||
}
|
||||
}
|
||||
}
|
||||
67
features/ue/ims_user/router.go
Normal file
67
features/ue/ims_user/router.go
Normal file
@@ -0,0 +1,67 @@
|
||||
package ims_user
|
||||
|
||||
import (
|
||||
"be.ems/src/framework/middleware"
|
||||
"be.ems/src/framework/middleware/collectlogs"
|
||||
"be.ems/src/framework/middleware/repeat"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// @Description Register Routes for ims_user
|
||||
func Register(r *gin.RouterGroup) {
|
||||
|
||||
volteUserGroup := r.Group("/volte/user")
|
||||
{
|
||||
volteUserGroup.PUT("/resetData/:neId",
|
||||
repeat.RepeatSubmit(5),
|
||||
middleware.PreAuthorize(nil),
|
||||
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.volteUser", collectlogs.BUSINESS_TYPE_CLEAN)),
|
||||
NewController.ResetData,
|
||||
)
|
||||
volteUserGroup.GET("/list",
|
||||
middleware.PreAuthorize(nil),
|
||||
NewController.List,
|
||||
)
|
||||
volteUserGroup.GET("/:neId/:imsi",
|
||||
middleware.PreAuthorize(nil),
|
||||
NewController.Info,
|
||||
)
|
||||
volteUserGroup.POST("/:neId",
|
||||
middleware.PreAuthorize(nil),
|
||||
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.volteUser", collectlogs.BUSINESS_TYPE_INSERT)),
|
||||
NewController.Add,
|
||||
)
|
||||
volteUserGroup.POST("/:neId/:num",
|
||||
middleware.PreAuthorize(nil),
|
||||
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.volteUser", collectlogs.BUSINESS_TYPE_INSERT)),
|
||||
NewController.Adds,
|
||||
)
|
||||
volteUserGroup.PUT("/:neId",
|
||||
middleware.PreAuthorize(nil),
|
||||
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.volteUser", collectlogs.BUSINESS_TYPE_UPDATE)),
|
||||
NewController.Edit,
|
||||
)
|
||||
volteUserGroup.DELETE("/:neId/:imsi",
|
||||
middleware.PreAuthorize(nil),
|
||||
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.volteUser", collectlogs.BUSINESS_TYPE_DELETE)),
|
||||
NewController.Remove,
|
||||
)
|
||||
volteUserGroup.DELETE("/:neId/:imsi/:num",
|
||||
middleware.PreAuthorize(nil),
|
||||
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.volteUser", collectlogs.BUSINESS_TYPE_DELETE)),
|
||||
NewController.Removes,
|
||||
)
|
||||
volteUserGroup.POST("/export",
|
||||
middleware.PreAuthorize(nil),
|
||||
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.volteUser", collectlogs.BUSINESS_TYPE_EXPORT)),
|
||||
NewController.Export,
|
||||
)
|
||||
volteUserGroup.POST("/import",
|
||||
middleware.PreAuthorize(nil),
|
||||
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.volteUser", collectlogs.BUSINESS_TYPE_IMPORT)),
|
||||
NewController.Import,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
209
features/ue/ims_user/service.go
Normal file
209
features/ue/ims_user/service.go
Normal file
@@ -0,0 +1,209 @@
|
||||
package ims_user
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"be.ems/src/framework/redis"
|
||||
neService "be.ems/src/modules/network_element/service"
|
||||
)
|
||||
|
||||
// 实例化服务层 Service 结构体
|
||||
var NewVoLTEService = &Service{
|
||||
volteRepository: NewVoLTERepository,
|
||||
}
|
||||
|
||||
// VoLTE用户信息 服务层处理
|
||||
type Service struct {
|
||||
volteRepository *Repository // VoLTE用户信息数据信息
|
||||
}
|
||||
|
||||
// dataByRedis UDM签约用户 db:0 中 volte:*
|
||||
func (r *Service) dataByRedis(imsi, neId string) []VoLTEUser {
|
||||
arr := []VoLTEUser{}
|
||||
key := fmt.Sprintf("volte:%s", imsi)
|
||||
source := fmt.Sprintf("UDM_%s", neId)
|
||||
|
||||
// 网元主机的Redis客户端
|
||||
redisClient, err := neService.NewNeInfo.NeRunRedisClient("UDM", neId)
|
||||
if err != nil {
|
||||
return arr
|
||||
}
|
||||
defer func() {
|
||||
redisClient.Close()
|
||||
redis.ConnectPush(source, nil)
|
||||
}()
|
||||
redis.ConnectPush(source, redisClient.Client)
|
||||
|
||||
udmsdArr, err := redis.GetKeys(source, key)
|
||||
if err != nil {
|
||||
return arr
|
||||
}
|
||||
mkv, err := redis.GetHashBatch(source, udmsdArr)
|
||||
if err != nil {
|
||||
return arr
|
||||
}
|
||||
|
||||
for k, m := range mkv {
|
||||
var imsi, msisdn string
|
||||
KeyParts := strings.Split(k, ":")
|
||||
switch len(KeyParts) {
|
||||
case 0, 1:
|
||||
// 处理单个部分的情况
|
||||
continue
|
||||
case 2:
|
||||
// 处理两个部分的情况
|
||||
imsi = KeyParts[1]
|
||||
msisdn = "-"
|
||||
case 3:
|
||||
// 处理三个部分的情况
|
||||
imsi = KeyParts[1]
|
||||
msisdn = KeyParts[2]
|
||||
default:
|
||||
// 处理更多部分的情况
|
||||
imsi = KeyParts[1]
|
||||
msisdn = KeyParts[2]
|
||||
}
|
||||
|
||||
var vni string = "-"
|
||||
impiParts := strings.Split(m["impi"], "@")
|
||||
if len(impiParts) > 1 {
|
||||
vni = impiParts[1] // 输出: ims.mnc001.mcc110.3gppnetwork.org
|
||||
}
|
||||
a := VoLTEUser{
|
||||
NeId: neId,
|
||||
IMSI: imsi, // volte:360000100000130:8612300000130
|
||||
MSISDN: msisdn, // 8612300000130
|
||||
VoLTE: m["tag"], // volte = tag
|
||||
VNI: vni, // ims.mnc001.mcc110.3gppnetwork.org
|
||||
}
|
||||
arr = append(arr, a)
|
||||
}
|
||||
return arr
|
||||
}
|
||||
|
||||
// ResetData 重置鉴权用户数据,清空数据库重新同步Redis数据
|
||||
func (r *Service) ResetData(neId string) int64 {
|
||||
subArr := r.dataByRedis("*", neId)
|
||||
// 数据清空后添加
|
||||
go r.volteRepository.ClearAndInsert(neId, subArr)
|
||||
return int64(len(subArr))
|
||||
}
|
||||
|
||||
// ParseInfo 解析单个用户imsi签约信息 data从命令MML得到的结果
|
||||
func (r *Service) ParseInfo(imsi, neId string, data map[string]string) VoLTEUser {
|
||||
u := r.volteRepository.SelectByIMSIAndNeID(imsi, neId)
|
||||
|
||||
msisdn := data["MSISDN"]
|
||||
if imsMsisdnLen := strings.Index(msisdn, ","); imsMsisdnLen != -1 {
|
||||
msisdn = msisdn[:imsMsisdnLen]
|
||||
}
|
||||
|
||||
// 用于更新
|
||||
u.NeId = neId
|
||||
u.IMSI = imsi
|
||||
u.MSISDN = msisdn
|
||||
u.VoLTE = data["VoLTE"]
|
||||
u.VNI = data["VNI"]
|
||||
return u
|
||||
}
|
||||
|
||||
// SelectPage 分页查询数据库
|
||||
func (r *Service) SelectPage(query map[string]any) map[string]any {
|
||||
return r.volteRepository.SelectPage(query)
|
||||
}
|
||||
|
||||
// SelectList 查询数据库
|
||||
func (r *Service) SelectList(u VoLTEUser) []VoLTEUser {
|
||||
return r.volteRepository.SelectList(u)
|
||||
}
|
||||
|
||||
// Insert 从数据中读取后删除imsi再存入数据库
|
||||
// imsi长度15,ki长度32,opc长度0或者32
|
||||
func (r *Service) Insert(neId string, u VoLTEUser) int64 {
|
||||
uArr := r.dataByRedis(u.IMSI, neId)
|
||||
if len(uArr) > 0 {
|
||||
r.volteRepository.Delete(u.IMSI, neId)
|
||||
return r.volteRepository.Inserts(uArr)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// InsertData 导入文件数据 dataType目前两种:txt/csv
|
||||
func (r *Service) InsertData(neId, dataType string, data any) int64 {
|
||||
// imsi截取前缀,重新获取部分数据
|
||||
prefixes := make(map[string]struct{})
|
||||
|
||||
if dataType == "csv" {
|
||||
for _, v := range data.([]map[string]string) {
|
||||
imsi := v["imsi"]
|
||||
if len(imsi) < 6 {
|
||||
continue
|
||||
}
|
||||
prefix := imsi[:len(imsi)-4]
|
||||
prefixes[prefix] = struct{}{}
|
||||
}
|
||||
}
|
||||
if dataType == "txt" {
|
||||
for _, v := range data.([][]string) {
|
||||
imsi := v[0]
|
||||
if len(imsi) < 6 {
|
||||
continue
|
||||
}
|
||||
prefix := imsi[:len(imsi)-4]
|
||||
prefixes[prefix] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
// 根据前缀重新加载插入
|
||||
var num int64 = 0
|
||||
for prefix := range prefixes {
|
||||
// keys volte:4600001000004*
|
||||
arr := r.dataByRedis(prefix+"*", neId)
|
||||
if len(arr) > 0 {
|
||||
r.volteRepository.DeletePrefixByIMSI(prefix, neId)
|
||||
num += r.volteRepository.Inserts(arr)
|
||||
}
|
||||
}
|
||||
return num
|
||||
}
|
||||
|
||||
// Delete 删除单个不重新加载
|
||||
func (r *Service) Delete(neId, imsi string) int64 {
|
||||
return r.volteRepository.Delete(imsi, neId)
|
||||
}
|
||||
|
||||
// LoadData 重新加载从imsi开始num的数据
|
||||
func (r *Service) LoadData(neId, imsi, num string) {
|
||||
startIMSI, _ := strconv.ParseInt(imsi, 10, 64)
|
||||
subNum, _ := strconv.ParseInt(num, 10, 64)
|
||||
var i int64
|
||||
for i = 0; i < subNum; i++ {
|
||||
keyIMSI := fmt.Sprintf("%015d", startIMSI+i)
|
||||
// 删除原数据
|
||||
r.volteRepository.Delete(keyIMSI, neId)
|
||||
arr := r.dataByRedis(keyIMSI, neId)
|
||||
if len(arr) < 1 {
|
||||
continue
|
||||
}
|
||||
r.volteRepository.Inserts(arr)
|
||||
}
|
||||
}
|
||||
|
||||
// ParseCommandParams 解析数据组成命令参数 msisdn=xx,xx=xx,...
|
||||
func (r *Service) ParseCommandParams(item VoLTEUser) string {
|
||||
var conditions []string
|
||||
if item.MSISDN != "" {
|
||||
conditions = append(conditions, fmt.Sprintf("msisdn=%s", item.MSISDN))
|
||||
}
|
||||
|
||||
if item.VoLTE != "" {
|
||||
conditions = append(conditions, fmt.Sprintf("volte=%s", item.VoLTE))
|
||||
}
|
||||
if item.VNI != "" {
|
||||
conditions = append(conditions, fmt.Sprintf("vni=%s", item.VNI))
|
||||
}
|
||||
|
||||
return strings.Join(conditions, ",")
|
||||
}
|
||||
Reference in New Issue
Block a user