diff --git a/features/udm_user/repo/repo_udm_sub_user.go b/features/udm_user/repo/repo_udm_sub_user.go index c7daf2a7..03ffdc04 100644 --- a/features/udm_user/repo/repo_udm_sub_user.go +++ b/features/udm_user/repo/repo_udm_sub_user.go @@ -95,8 +95,10 @@ func (r *RepoUdmSubUser) SelectPage(query map[string]any) map[string]any { if err != nil { log.Errorf("Find tenant_id err => %v", err) } - conditions = append(conditions, "s.tenant_id = ?") - params = append(params, tenantID[0]) + if len(tenantID) > 0 { + conditions = append(conditions, "s.tenant_id = ?") + params = append(params, tenantID[0]) + } } // 构建查询条件语句 @@ -182,8 +184,10 @@ func (r *RepoUdmSubUser) SelectList(auth model.UdmSubUser) []model.UdmSubUser { if err != nil { log.Errorf("Find tenant_id err => %v", err) } - conditions = append(conditions, "s.tenant_id = ?") - params = append(params, tenantID[0]) + if len(tenantID) > 0 { + conditions = append(conditions, "s.tenant_id = ?") + params = append(params, tenantID[0]) + } } // 构建查询条件语句 @@ -504,7 +508,9 @@ func (r *RepoUdmSubUser) SetTenantName(subArr *[]model.UdmSubUser) { log.Errorf("Find tenant_name err => %v", err) continue } - (*subArr)[s].TenantName = tenantName[0] + if len(tenantName) > 0 { + (*subArr)[s].TenantID = tenantName[0] + } } } @@ -518,7 +524,8 @@ func (r *RepoUdmSubUser) SetTenantID(subArr *[]model.UdmSubUser) { log.Errorf("Find tenant_id err => %v", err) continue } - (*subArr)[s].TenantID = tenantID[0] - fmt.Printf("IMSI: %s, tenantID:%s", (*subArr)[s].Imsi, tenantID[0]) + if len(tenantID) > 0 { + (*subArr)[s].TenantID = tenantID[0] + } } } diff --git a/features/ue/ue.go b/features/ue/ue.go index 279e24b9..4278befc 100644 --- a/features/ue/ue.go +++ b/features/ue/ue.go @@ -8,6 +8,7 @@ import ( "strings" "time" + "be.ems/lib/core/utils/ctx" "be.ems/lib/dborm" "be.ems/lib/global" "be.ems/lib/log" @@ -18,38 +19,11 @@ import ( "github.com/gorilla/mux" ) -// AmfNBInfo AMF的NodeB信息 -type AmfNBInfo struct { - ID string `json:"id"` //NodeB ID - Name string `json:"name"` // NodeB name - Address string `json:"address"` // 基站地址 - UENum int `jons:"ueNum"` // UE数量 -} - // SmfUENum SMF在线用户数 type SmfUENum struct { UENum int `json:"ueNum"` // 当前在线用户数 } -// SmfUEInfo SMF在线用户信息 -type SmfUEInfo struct { - IMSI string `json:"imsi"` - MSISDN string `json:"msisdn"` - RatType string `json:"ratType"` - PduSessionInfo []struct { - PduSessionID int `json:"pduSessionID"` - IPv4 string `json:"ipv4"` - IPv6 string `json:"ipv6"` - Dnn string `json:"dnn"` - Tai string `json:"tai"` - SstSD string `json:"sstSD"` - UpfN3IP string `json:"upfN3IP"` - RanN3IP string `json:"ranN3IP"` - Activetime string `json:"activeTime"` - UpState string `json:"upState"` - } `json:"pduSessionInfo"` -} - // ImsUEInfo IMS在线用户信息 type ImsUEInfo struct { IMSI string `json:"imsi"` @@ -239,7 +213,53 @@ func GetSubscriptionsFromNSSF(w http.ResponseWriter, r *http.Request) { } } -// Get UEInfo from NF/NFs +// SmfUEInfo SMF在线用户信息 +type SmfUEInfo struct { + IMSI string `json:"imsi"` + MSISDN string `json:"msisdn"` + RatType string `json:"ratType"` + PduSessionInfo []struct { + PduSessionID int `json:"pduSessionID"` + IPv4 string `json:"ipv4"` + IPv6 string `json:"ipv6"` + Dnn string `json:"dnn"` + Tai string `json:"tai"` + SstSD string `json:"sstSD"` + UpfN3IP string `json:"upfN3IP"` + RanN3IP string `json:"ranN3IP"` + Activetime string `json:"activeTime"` + UpState string `json:"upState"` + } `json:"pduSessionInfo"` +} + +type TenantUEInfo struct { + IMSI string `json:"imsi"` + MSISDN string `json:"msisdn"` + RatType string `json:"ratType"` + PduSessionInfo []struct { + PduSessionID int `json:"pduSessionID"` + IPv4 string `json:"ipv4"` + IPv6 string `json:"ipv6"` + Dnn string `json:"dnn"` + Tai string `json:"tai"` + SstSD string `json:"sstSD"` + UpfN3IP string `json:"upfN3IP"` + RanN3IP string `json:"ranN3IP"` + Activetime string `json:"activeTime"` + UpState string `json:"upState"` + } `json:"pduSessionInfo"` + TenantName string `json:"tenantName"` +} + +type SmfUEInfoResponse struct { + Data []SmfUEInfo `json:"data"` +} + +type UEInfoResponse struct { + Data []TenantUEInfo `json:"data"` +} + +// Get UEInfo from NF/NFs, SMF Online users func GetUEInfoFromNF(w http.ResponseWriter, r *http.Request) { log.Info("GetUEInfoFromNF processing... ") @@ -258,7 +278,11 @@ func GetUEInfoFromNF(w http.ResponseWriter, r *http.Request) { services.ResponseNotFound404UriNotExist(w, r) return } - + var tenantName string + tenantNames := services.GetParamsArrByName("tenantName", r) + if len(tenantNames) > 0 { + tenantName = tenantNames[0] + } // token, err := services.CheckFrontValidRequest(w, r) // if err != nil { // log.Error("Request error:", err) @@ -281,6 +305,9 @@ func GetUEInfoFromNF(w http.ResponseWriter, r *http.Request) { hostUri := fmt.Sprintf("http://%s:%v", neInfo.Ip, neInfo.Port) requestURI2NF := fmt.Sprintf("%s%s", hostUri, r.RequestURI) + // for apifox mock test + // hostUri := "http://127.0.0.1:4523" + // requestURI2NF := hostUri + "/m1/3157310-1528434-default/api/rest/ueManagement/v1/elementType/smf/objectType/ueInfo?apifoxApiId=128609449" log.Debug("requestURI2NF:", requestURI2NF) @@ -296,14 +323,56 @@ func GetUEInfoFromNF(w http.ResponseWriter, r *http.Request) { services.ResponseInternalServerError500ProcessError(w, err) return } else { - var response services.MapResponse - _ = json.Unmarshal(resp.Body(), &response) - services.ResponseWithJson(w, resp.StatusCode(), response) - return + // multi-tenancy solution + var tenantID, where string + //var cols []string + if tenantName != "" { + where = fmt.Sprintf("status='1' and tenant_name='%s'", tenantName) + tenantID, _ = dborm.XormGetSingleColStringByWhere("sys_tenant", "tenant_id", where) + } else { + userName := ctx.LoginUserToUserName(r) + where = fmt.Sprintf("status='1' and user_name='%s'", userName) + tenantID, _ = dborm.XormGetSingleColStringByWhere("sys_user", "tenant_id", where) + where = fmt.Sprintf("status='1' and tenant_id='%s'", tenantID) + tenantName, _ = dborm.XormGetSingleColStringByWhere("sys_tenant", "tenant_name", where) + } + if tenantID == "" { + var response UEInfoResponse + _ = json.Unmarshal(resp.Body(), &response) + for i := 0; i < len(response.Data); i++ { + where = fmt.Sprintf("status='1' and tenancy_type='IMSI' and '%s' like tenancy_key", response.Data[i].IMSI[5:]) + tenantID, _ = dborm.XormGetSingleColStringByWhere("sys_tenant", "parent_id", where) + where = fmt.Sprintf("status='1' and tenant_id='%s'", tenantID) + tenantName, _ = dborm.XormGetSingleColStringByWhere("sys_tenant", "tenant_name", where) + log.Tracef("tenantName: %s tenantID: %s", tenantName, tenantID) + response.Data[i].TenantName = tenantName + } + services.ResponseWithJson(w, resp.StatusCode(), &response) + } else { + var tenantUEInfos []TenantUEInfo + var ueInfos UEInfoResponse + log.Trace("body:", string(resp.Body())) + _ = json.Unmarshal(resp.Body(), &ueInfos) + log.Trace("ueInfos:", ueInfos) + for _, n := range ueInfos.Data { + log.Trace("tenantID, n.IMSI[5:]:", tenantID, n.IMSI[5:]) + // "imsi": "imsi-460000100029999", + where = fmt.Sprintf("status='1' and parent_id='%s' and tenancy_type='IMSI' and '%s' like tenancy_key", tenantID, n.IMSI[5:]) + has, err := dborm.XormExistTableOne("sys_tenant", where) + if err == nil && has { + n.TenantName = tenantName + tenantUEInfos = append(tenantUEInfos, n) + } + } + var response UEInfoResponse + response.Data = tenantUEInfos + services.ResponseWithJson(w, resp.StatusCode(), &response) + return + } } } -// POST User Info from NF/NFs +// POST PCF User Info from NF/NFs func PostPCFUserInfo(w http.ResponseWriter, r *http.Request) { log.Info("PostPCFUserInfo processing... ") @@ -580,7 +649,27 @@ func GetUENumFromNF(w http.ResponseWriter, r *http.Request) { } } -// Get Radio Info from NF/NFs +// AmfNBInfo AMF的NodeB信息 +type AmfNBInfo struct { + ID string `json:"id"` //NodeB ID + Name string `json:"name"` // NodeB name + Address string `json:"address"` // 基站地址 + UENum int `json:"ueNum"` // UE数量 +} + +type TenantNBInfo struct { + ID string `json:"id"` //NodeB ID + Name string `json:"name"` // NodeB name + Address string `json:"address"` // 基站地址 + UENum int `json:"ueNum"` // UE数量 + TenantName string `json:"tenantName"` // Tenant Name +} + +type NBInfoResponse struct { + Data []TenantNBInfo `json:"data"` +} + +// Get AMF Radio Info from NF/NFs func GetNBInfoFromNF(w http.ResponseWriter, r *http.Request) { log.Info("GetNBInfoFromNF processing... ") @@ -599,7 +688,11 @@ func GetNBInfoFromNF(w http.ResponseWriter, r *http.Request) { services.ResponseNotFound404UriNotExist(w, r) return } - + var tenantName string + tenantNames := services.GetParamsArrByName("tenantName", r) + if len(tenantNames) > 0 { + tenantName = tenantNames[0] + } // token, err := services.CheckFrontValidRequest(w, r) // if err != nil { // log.Error("Request error:", err) @@ -623,6 +716,10 @@ func GetNBInfoFromNF(w http.ResponseWriter, r *http.Request) { hostUri := fmt.Sprintf("http://%s:%v", neInfo.Ip, neInfo.Port) requestURI2NF := fmt.Sprintf("%s%s", hostUri, r.RequestURI) + // for apifox mock test + // hostUri := "http://127.0.0.1:4523" + // requestURI2NF := hostUri + "/m1/3157310-1528434-default/api/rest/ueManagement/v1/elementType/amf/objectType/nbInfo?apifoxApiId=128848301" + log.Debug("requestURI2NF:", requestURI2NF) resp, err := client.R(). @@ -637,10 +734,52 @@ func GetNBInfoFromNF(w http.ResponseWriter, r *http.Request) { services.ResponseInternalServerError500ProcessError(w, err) return } else { - var response services.MapResponse - _ = json.Unmarshal(resp.Body(), &response) - services.ResponseWithJson(w, resp.StatusCode(), response) - return + // multi-tenancy solution + var tenantID, where, userName string + if tenantName != "" { + where = fmt.Sprintf("status='1' and tenant_name='%s'", tenantName) + tenantID, _ = dborm.XormGetSingleColStringByWhere("sys_tenant", "tenant_id", where) + } else { + userName = ctx.LoginUserToUserName(r) + where = fmt.Sprintf("status='1' and user_name='%s'", userName) + tenantID, _ = dborm.XormGetSingleColStringByWhere("sys_user", "tenant_id", where) + where = fmt.Sprintf("status='1' and tenant_id='%s'", tenantID) + tenantName, _ = dborm.XormGetSingleColStringByWhere("sys_tenant", "tenant_name", where) + } + log.Tracef("tenantName: %s userName: %s tenantID: %s", tenantName, userName, tenantID) + if tenantID == "" { + var response NBInfoResponse + //var nbInfo *TenantNBInfo + _ = json.Unmarshal(resp.Body(), &response) + for i := 0; i < len(response.Data); i++ { + where = fmt.Sprintf("status='1' and tenancy_type='RADIO' and tenancy_key='%s'", response.Data[i].ID) + tenantID, _ = dborm.XormGetSingleColStringByWhere("sys_tenant", "parent_id", where) + where = fmt.Sprintf("status='1' and tenant_id='%s'", tenantID) + tenantName, _ = dborm.XormGetSingleColStringByWhere("sys_tenant", "tenant_name", where) + log.Tracef("tenantName: %s tenantID: %s", tenantName, tenantID) + response.Data[i].TenantName = tenantName + } + services.ResponseWithJson(w, resp.StatusCode(), &response) + } else { + // var response services.MapResponse + var tenantNBInfos []TenantNBInfo + var nbInfos NBInfoResponse + var nbIDs []string + // Get nodeB IDs by tenantID + where = fmt.Sprintf("status='1' and tenancy_type='RADIO' and parent_id='%s'", tenantID) + dborm.XormFindColStringArrayByWhere("sys_tenant", "tenancy_key", where, &nbIDs) + _ = json.Unmarshal(resp.Body(), &nbInfos) + for _, n := range nbInfos.Data { + if global.IsMember(n.ID, nbIDs) { + n.TenantName = tenantName + tenantNBInfos = append(tenantNBInfos, n) + } + } + log.Tracef("nbIDs: %v", nbIDs) + nbInfos.Data = tenantNBInfos + services.ResponseWithJson(w, resp.StatusCode(), &nbInfos) + return + } } } diff --git a/lib/dborm/dborm.go b/lib/dborm/dborm.go index aa008291..8bf8f918 100644 --- a/lib/dborm/dborm.go +++ b/lib/dborm/dborm.go @@ -1286,9 +1286,9 @@ func XormGetColStringArrayByWhere(table, coln, where string, colv *[]string) err func XormFindColStringArrayByWhere(table, col, where string, cols *[]string) error { log.Debug("XormFindColStringArrayByWhere processing... ") - err := xEngine.Table(table).Where(where).Cols(col).Distinct().Find(cols) + err := xEngine.Table(table).Where(where).Cols(col).Find(cols) if err != nil { - log.Errorf("Failed to Find %s from table %s:%v", col, table, err) + log.Errorf("Failed to find %s from table %s: %v", col, table, err) return err } return nil @@ -1300,7 +1300,7 @@ func XormGetSingleColStringByWhere(table, col, where string) (string, error) { var colv string _, err := xEngine.Table(table).Where(where).Cols(col).Get(&colv) if err != nil { - log.Errorf("Failed to Find %s from table %s:%v", col, table, err) + log.Errorf("Failed to find %s from table %s: %v", col, table, err) return colv, err } return colv, nil diff --git a/lib/global/kits.go b/lib/global/kits.go index 22091f08..62df5b8a 100644 --- a/lib/global/kits.go +++ b/lib/global/kits.go @@ -726,3 +726,12 @@ func RecurseStructToMap(obj any) map[string]any { } return out } + +func IsMember(target string, group []string) bool { + for _, str := range group { + if target == str { + return true + } + } + return false +} diff --git a/lib/routes/routes.go b/lib/routes/routes.go index baddb754..ac432a9a 100644 --- a/lib/routes/routes.go +++ b/lib/routes/routes.go @@ -269,7 +269,7 @@ func init() { Register("GET", ue.UriUENum, ue.GetUENumFromNF, nil) Register("GET", ue.CustomUriUENum, ue.GetUENumFromNF, nil) - // NBInfo + // AMF NBInfo Register("GET", ue.UriNBInfo, ue.GetNBInfoFromNF, nil) Register("GET", ue.CustomUriNBInfo, ue.GetNBInfoFromNF, nil) diff --git a/src/modules/network_element/controller/udm_sub.go b/src/modules/network_element/controller/udm_sub.go index 80bf805a..1fbcc73f 100644 --- a/src/modules/network_element/controller/udm_sub.go +++ b/src/modules/network_element/controller/udm_sub.go @@ -58,6 +58,7 @@ func (s *UDMSubController) ResetData(c *gin.Context) { func (s *UDMSubController) List(c *gin.Context) { querys := ctx.QueryMap(c) querys["neId"] = "" + querys["userName"] = ctx.LoginUserToUserName(c) data := s.udmSubService.Page(querys) c.JSON(200, result.Ok(data)) } diff --git a/src/modules/network_element/repository/udm_sub.impl.go b/src/modules/network_element/repository/udm_sub.impl.go index 1786c4a8..fd293f38 100644 --- a/src/modules/network_element/repository/udm_sub.impl.go +++ b/src/modules/network_element/repository/udm_sub.impl.go @@ -106,10 +106,25 @@ func (r *UDMSubImpl) SelectPage(query map[string]any) map[string]any { err := dborm.DefaultDB().Table("sys_tenant"). Where("tenant_name=?", v).Cols("tenant_id").Distinct().Find(&tenantID) if err != nil { - log.Errorf("Find tenant_id err => %v", err) + 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().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]) } - conditions = append(conditions, "s.tenant_id = ?") - params = append(params, tenantID[0]) } // 构建查询条件语句 @@ -339,7 +354,7 @@ func (r *UDMSubImpl) SetTenantID(subArr *[]model.UDMSub) { for s := 0; s < len(*subArr); s++ { var tenantID []string err := dborm.DefaultDB().Table("sys_tenant"). - Where("tenancy_type='IMSI' and tenancy_key=?", (*subArr)[s].Imsi).Cols("parent_id").Distinct().Find(&tenantID) + Where("status='1' and tenancy_type='IMSI' and ? like tenancy_key", (*subArr)[s].Imsi).Cols("parent_id").Distinct().Find(&tenantID) if err != nil { log.Errorf("Find tenant_id err => %v", err) continue diff --git a/src/modules/system/controller/sys_log_operate.go b/src/modules/system/controller/sys_log_operate.go index 3c542a9c..1a778669 100644 --- a/src/modules/system/controller/sys_log_operate.go +++ b/src/modules/system/controller/sys_log_operate.go @@ -15,6 +15,7 @@ import ( "be.ems/src/modules/system/model" "be.ems/src/modules/system/service" + dborm "be.ems/lib/core/datasource" "github.com/gin-gonic/gin" ) @@ -42,6 +43,11 @@ func (s *SysLogOperateController) List(c *gin.Context) { querys["title"] = i18n.TFindKeyPrefix(language, "log.operate.title", v.(string)) } + // multi-tenancy, only filter user setting tenant_id + userName := ctx.LoginUserToUserName(c) + if s.IsTenancyUser(userName) { + querys["operName"] = userName + } data := s.SysLogOperateService.SelectSysLogOperatePage(querys) rows := data["rows"].([]model.SysLogOperate) @@ -204,3 +210,12 @@ func (s *SysLogOperateController) Export(c *gin.Context) { c.FileAttachment(saveFilePath, fileName) } + +func (s *SysLogOperateController) IsTenancyUser(userName string) bool { + var tenantID []int64 + dborm.DefaultDB().Table("sys_user").Where("user_name=?", userName).Cols("tenant_id").Find(&tenantID) + if len(tenantID) > 0 { + return true + } + return false +} diff --git a/src/modules/system/repository/sys_log_operate.impl.go b/src/modules/system/repository/sys_log_operate.impl.go index 649c3123..f8a753fe 100644 --- a/src/modules/system/repository/sys_log_operate.impl.go +++ b/src/modules/system/repository/sys_log_operate.impl.go @@ -99,6 +99,12 @@ func (r *SysLogOperateImpl) SelectSysLogOperatePage(query map[string]any) map[st params = append(params, parse.Number(endTime.(string))) } + // multi-tenancy, only filter user setting tenant_id + if v, ok := query["operName"]; ok && v != "" { + conditions = append(conditions, "oper_name=?") + params = append(params, v) + } + // 构建查询条件语句 whereSql := "" if len(conditions) > 0 {