Merge branch 'lichang' into lite
This commit is contained in:
40
src/app.go
40
src/app.go
@@ -7,12 +7,15 @@ import (
|
||||
"be.ems/src/framework/errorcatch"
|
||||
"be.ems/src/framework/middleware"
|
||||
"be.ems/src/framework/middleware/security"
|
||||
|
||||
"be.ems/src/modules/auth"
|
||||
"be.ems/src/modules/chart"
|
||||
"be.ems/src/modules/common"
|
||||
"be.ems/src/modules/crontask"
|
||||
"be.ems/src/modules/monitor"
|
||||
networkdata "be.ems/src/modules/network_data"
|
||||
networkelement "be.ems/src/modules/network_element"
|
||||
"be.ems/src/modules/oauth2"
|
||||
"be.ems/src/modules/system"
|
||||
"be.ems/src/modules/tool"
|
||||
"be.ems/src/modules/trace"
|
||||
@@ -21,26 +24,8 @@ import (
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// AppEngine 路由函数句柄,交给由 http.ListenAndServe(addr, router)
|
||||
func AppEngine() *gin.Engine {
|
||||
app := initAppEngine()
|
||||
|
||||
// 初始全局默认
|
||||
initDefeat(app)
|
||||
|
||||
// 初始模块路由
|
||||
initModulesRoute(app)
|
||||
|
||||
// 首次安装启动记录
|
||||
// machine.Launch()
|
||||
|
||||
// 读取服务配置
|
||||
app.ForwardedByClientIP = config.Get("server.proxy").(bool)
|
||||
return app
|
||||
}
|
||||
|
||||
// 初始应用引擎
|
||||
func initAppEngine() *gin.Engine {
|
||||
func AppEngine() *gin.Engine {
|
||||
var app *gin.Engine
|
||||
|
||||
// 禁止控制台日志输出的颜色
|
||||
@@ -54,12 +39,12 @@ func initAppEngine() *gin.Engine {
|
||||
} else {
|
||||
app = gin.Default()
|
||||
}
|
||||
|
||||
app.ForwardedByClientIP = true
|
||||
return app
|
||||
}
|
||||
|
||||
// 初始全局默认
|
||||
func initDefeat(app *gin.Engine) {
|
||||
func DefeatConfig(app *gin.Engine) {
|
||||
// 全局中间件
|
||||
if config.Env() == "local" {
|
||||
app.Use(middleware.Report())
|
||||
@@ -94,15 +79,21 @@ func initDefeat(app *gin.Engine) {
|
||||
}
|
||||
|
||||
// 初始模块路由
|
||||
func initModulesRoute(app *gin.Engine) {
|
||||
// 通用模块
|
||||
common.Setup(app)
|
||||
func ModulesRoute(app *gin.Engine) {
|
||||
// 系统模块
|
||||
system.Setup(app)
|
||||
// 认证模块
|
||||
auth.Setup(app)
|
||||
// 开放客户端模块
|
||||
oauth2.Setup(app)
|
||||
// 通用模块
|
||||
common.Setup(app)
|
||||
|
||||
// 网元功能模块
|
||||
networkelement.Setup(app)
|
||||
// 网元数据模块
|
||||
networkdata.Setup(app)
|
||||
|
||||
// 跟踪模块
|
||||
trace.Setup(app)
|
||||
// 图表模块
|
||||
@@ -111,6 +102,7 @@ func initModulesRoute(app *gin.Engine) {
|
||||
tool.Setup(app)
|
||||
// ws 模块
|
||||
ws.Setup(app)
|
||||
|
||||
// 调度任务模块--暂无接口
|
||||
crontask.Setup(app)
|
||||
// 监控模块 - 含调度处理加入队列,放最后
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
# 应用服务配置
|
||||
server:
|
||||
# 是否开启代理
|
||||
proxy: false
|
||||
# 运行版本 std/lite
|
||||
serverVersion: "std"
|
||||
# 运行模式 system/docker
|
||||
serverMode: "system"
|
||||
# 登录认证,默认打开
|
||||
serverLoginAuth: true
|
||||
# 接口加密,默认关闭
|
||||
serverCryptoApi: false
|
||||
|
||||
# 日志
|
||||
logger:
|
||||
@@ -131,33 +135,33 @@ security:
|
||||
# JWT 令牌配置
|
||||
jwt:
|
||||
# 令牌算法 HS256 HS384 HS512
|
||||
algorithm: "HS512"
|
||||
algorithm: "HS256"
|
||||
# 令牌密钥
|
||||
secret: "217a0481c7f9cfe1cb547d32ee012b0f"
|
||||
# 令牌有效期(默认120分钟)
|
||||
expiresIn: 120
|
||||
# 验证令牌有效期,相差不足xx分钟,自动刷新缓存
|
||||
refreshIn: 20
|
||||
# 访问令牌有效期(默认15分钟)
|
||||
expiresIn: 15
|
||||
# 刷新令牌有效期(默认7*24*60分钟)
|
||||
refreshIn: 10080
|
||||
|
||||
# DB 数据源
|
||||
database:
|
||||
dataSource:
|
||||
# 默认数据库实例
|
||||
# default:
|
||||
# type: "mysql"
|
||||
# host: "127.0.0.1"
|
||||
# port: 3306
|
||||
# username: "<username>"
|
||||
# password: "<password>"
|
||||
# database: "<database>"
|
||||
# logging: false
|
||||
std:
|
||||
type: "mysql"
|
||||
host: "127.0.0.1"
|
||||
port: 3306
|
||||
username: "<username>"
|
||||
password: "<password>"
|
||||
database: "<database>"
|
||||
logging: false
|
||||
# 内置轻量级数据库
|
||||
lite:
|
||||
type: "sqlite"
|
||||
database: "<database path>"
|
||||
logging: false
|
||||
# 多个数据源时可以用这个指定默认的数据源
|
||||
defaultDataSourceName: "default"
|
||||
defaultDataSourceName: "std"
|
||||
|
||||
# Redis 缓存数据
|
||||
redis:
|
||||
@@ -179,21 +183,9 @@ aes:
|
||||
# 应用密钥
|
||||
appKey: "E83dbfeb35BA4839232e2761b0FE5f32"
|
||||
|
||||
# 用户配置
|
||||
user:
|
||||
# 登录认证,默认打开
|
||||
loginAuth: true
|
||||
# 接口加密,默认打开
|
||||
cryptoApi: false
|
||||
# 密码
|
||||
password:
|
||||
# 密码最大错误次数
|
||||
maxRetryCount: 5
|
||||
# 密码锁定时间,单位分钟(默认10分钟)
|
||||
lockTime: 10
|
||||
# 设定为系统管理员的用户ID
|
||||
system:
|
||||
- 1
|
||||
# 设定为系统管理员的用户ID
|
||||
systemUser:
|
||||
- 1
|
||||
|
||||
# char 字符验证码配置
|
||||
charCaptcha:
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
# 应用服务配置
|
||||
server:
|
||||
proxy: true
|
||||
|
||||
# 日志
|
||||
logger:
|
||||
fileDir: "C:/var/log"
|
||||
fileDir: "/var/log"
|
||||
fileName: "omc.log"
|
||||
level: 0 # 日志记录的等级 0:silent<1:info<2:warn<3:error
|
||||
maxDay: 7 # 日志会保留 180 天
|
||||
@@ -15,31 +11,31 @@ staticFile:
|
||||
# 默认资源,dir目录需要预先创建
|
||||
default:
|
||||
prefix: "/static"
|
||||
dir: "C:/usr/local/omc/static"
|
||||
dir: "/usr/local/omc/static"
|
||||
# 文件上传资源目录映射,与项目目录同级
|
||||
upload:
|
||||
prefix: "/upload"
|
||||
dir: "C:/usr/local/omc/upload"
|
||||
dir: "/usr/local/omc/upload"
|
||||
|
||||
# DB 数据源
|
||||
database:
|
||||
dataSource:
|
||||
# 默认数据库实例
|
||||
# default:
|
||||
# type: "mysql"
|
||||
# host: "127.0.0.1"
|
||||
# port: 3306
|
||||
# username: "<username>"
|
||||
# password: "<password>"
|
||||
# database: "<database>"
|
||||
# logging: false
|
||||
std:
|
||||
type: "mysql"
|
||||
host: "127.0.0.1"
|
||||
port: 3306
|
||||
username: "root"
|
||||
password: "1000omc@kp!"
|
||||
database: "omc_db"
|
||||
logging: true
|
||||
# 内置轻量级数据库
|
||||
lite:
|
||||
type: "sqlite"
|
||||
database: "<database path>"
|
||||
logging: false
|
||||
database: "/usr/local/etc/omc/database/omc_db.sqlite"
|
||||
logging: true
|
||||
# 多个数据源时可以用这个指定默认的数据源
|
||||
defaultDataSourceName: "lite"
|
||||
defaultDataSourceName: "std"
|
||||
|
||||
# Redis 缓存数据
|
||||
redis:
|
||||
@@ -47,7 +43,7 @@ redis:
|
||||
default:
|
||||
port: 6379 # Redis port
|
||||
host: "127.0.0.1" # Redis host
|
||||
password: "<password>"
|
||||
password: "helloearth"
|
||||
db: 0 # Redis db_num
|
||||
# 多个数据源时可以用这个指定默认的数据源
|
||||
defaultDataSourceName: "default"
|
||||
|
||||
@@ -1,27 +1,22 @@
|
||||
# 应用服务配置
|
||||
server:
|
||||
# 是否开启代理
|
||||
proxy: true
|
||||
|
||||
# DB 数据源
|
||||
database:
|
||||
dataSource:
|
||||
# 默认数据库实例
|
||||
# default:
|
||||
# type: "mysql"
|
||||
# host: "127.0.0.1"
|
||||
# port: 3306
|
||||
# username: "<username>"
|
||||
# password: "<password>"
|
||||
# database: "<database>"
|
||||
# logging: false
|
||||
std:
|
||||
type: "mysql"
|
||||
host: "127.0.0.1"
|
||||
port: 33066
|
||||
username: "root"
|
||||
password: "1000omc@kp!"
|
||||
database: "omc_db"
|
||||
logging: false
|
||||
# 内置轻量级数据库
|
||||
lite:
|
||||
type: "sqlite"
|
||||
database: "/usr/local/omc/database/omc_db.sqlite"
|
||||
database: "/usr/local/etc/omc/database/omc_db.sqlite"
|
||||
logging: false
|
||||
# 多个数据源时可以用这个指定默认的数据源
|
||||
defaultDataSourceName: "lite"
|
||||
defaultDataSourceName: "std"
|
||||
|
||||
# Redis 缓存数据
|
||||
redis:
|
||||
@@ -30,6 +25,6 @@ redis:
|
||||
port: 6379 # Redis port
|
||||
host: "127.0.0.1" # Redis host
|
||||
password: "helloearth"
|
||||
db: 10 # Redis db_num
|
||||
db: 0 # Redis db_num
|
||||
# 多个数据源时可以用这个指定默认的数据源
|
||||
defaultDataSourceName: "default"
|
||||
|
||||
@@ -12,9 +12,15 @@ import (
|
||||
"github.com/spf13/viper"
|
||||
|
||||
libConfig "be.ems/lib/config"
|
||||
libGlobal "be.ems/lib/global"
|
||||
)
|
||||
|
||||
var (
|
||||
Version string = "-"
|
||||
BuildTime string = "-"
|
||||
GoVer string = "-"
|
||||
)
|
||||
|
||||
// 程序配置
|
||||
var conf *viper.Viper
|
||||
|
||||
// 初始化程序配置
|
||||
@@ -28,9 +34,9 @@ func InitConfig(configDir *embed.FS) {
|
||||
func initFlag() {
|
||||
// --env prod
|
||||
pflag.String("env", "prod", "Specify Run Environment Configuration local or prod")
|
||||
// --c /etc/restconf.yaml
|
||||
// -c /etc/restconf.yaml
|
||||
pflag.StringP("config", "c", "./etc/restconf.yaml", "Specify Configuration File")
|
||||
// --c /usr/local/etc/omc/omc.yaml
|
||||
// -c /usr/local/etc/omc/omc.yaml
|
||||
pflag.StringP("config", "c", "/usr/local/etc/omc/omc.yaml", "Specify Configuration File")
|
||||
// --sqlPath ./sql/20250228.sql
|
||||
pflag.String("sqlPath", "", "Execution SQL File Path")
|
||||
// --sqlSource default
|
||||
@@ -45,7 +51,7 @@ func initFlag() {
|
||||
|
||||
// 参数固定输出
|
||||
if *pVersion {
|
||||
buildInfo := fmt.Sprintf("OMC version: %s\n%s\n%s\n\n", libGlobal.Version, libGlobal.BuildTime, libGlobal.GoVer)
|
||||
buildInfo := fmt.Sprintf("OMC \nBuildVer: %s\nBuildTime: %s\nBuildEnv: %s\n", Version, BuildTime, GoVer)
|
||||
fmt.Println(buildInfo)
|
||||
os.Exit(1)
|
||||
}
|
||||
@@ -74,7 +80,7 @@ func initViper(configDir *embed.FS) {
|
||||
|
||||
// 当期服务环境运行配置 => local
|
||||
env := conf.GetString("env")
|
||||
log.Printf("current service environment operation configuration => %s \n", env)
|
||||
log.Printf("current service environment configuration => %s \n", env)
|
||||
|
||||
// 加载运行配置文件合并相同配置
|
||||
envConfigPath := fmt.Sprintf("config/config.%s.yaml", env)
|
||||
@@ -160,7 +166,7 @@ func RunTime() time.Time {
|
||||
|
||||
// Get 获取配置信息
|
||||
//
|
||||
// Get("server.proxy")
|
||||
// Get("redis.defaultDataSourceName")
|
||||
func Get(key string) any {
|
||||
return conf.Get(key)
|
||||
}
|
||||
@@ -181,7 +187,7 @@ func IsSystemUser(userId int64) bool {
|
||||
return false
|
||||
}
|
||||
// 从配置中获取系统管理员ID列表
|
||||
arr := Get("user.system").([]any)
|
||||
arr := Get("systemUser").([]any)
|
||||
for _, v := range arr {
|
||||
if fmt.Sprint(v) == fmt.Sprint(userId) {
|
||||
return true
|
||||
|
||||
@@ -2,8 +2,8 @@ package constants
|
||||
|
||||
// 缓存的key常量
|
||||
const (
|
||||
// CACHE_LOGIN_TOKEN 登录用户
|
||||
CACHE_LOGIN_TOKEN = "login_tokens"
|
||||
// CACHE_TOKEN_DEVICE 登录用户令牌标识
|
||||
CACHE_TOKEN_DEVICE = "token_devices"
|
||||
// CACHE_CAPTCHA_CODE 验证码
|
||||
CACHE_CAPTCHA_CODE = "captcha_codes"
|
||||
// CACHE_SYS_CONFIG 参数管理
|
||||
@@ -16,6 +16,10 @@ const (
|
||||
CACHE_RATE_LIMIT = "rate_limit"
|
||||
// CACHE_PWD_ERR_COUNT 登录账户密码错误次数
|
||||
CACHE_PWD_ERR_COUNT = "pwd_err_count"
|
||||
// CACHE_OAUTH2_DEVICE 授权客户端令牌标识
|
||||
CACHE_OAUTH2_DEVICE = "oauth2_devices"
|
||||
// CACHE_OAUTH2_CODE 客户端授权码
|
||||
CACHE_OAUTH2_CODE = "oauth2_codes"
|
||||
// CACHE_I18N 国际化语言管理
|
||||
CACHE_I18N = "i18n"
|
||||
// CACHE_NE_INFO 网元信息管理
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
package constants
|
||||
|
||||
// 验证码常量信息
|
||||
const (
|
||||
// CAPTCHA_EXPIRATION 验证码有效期,单位秒
|
||||
CAPTCHA_EXPIRATION = 2 * 60
|
||||
// CAPTCHA_TYPE_CHAR 验证码类型-数值计算
|
||||
CAPTCHA_TYPE_CHAR = "char"
|
||||
// CAPTCHA_TYPE_MATH 验证码类型-字符验证
|
||||
CAPTCHA_TYPE_MATH = "math"
|
||||
)
|
||||
@@ -10,5 +10,8 @@ const (
|
||||
// CTX_LOGIN_USER 上下文信息-登录用户
|
||||
const CTX_LOGIN_USER = "ctx:login_user"
|
||||
|
||||
// CTX_LOGIN_OAUTH2 上下文信息-认证客户端
|
||||
const CTX_LOGIN_OAUTH2 = "ctx:login_oauth2"
|
||||
|
||||
// 启动-引导系统初始
|
||||
const LAUNCH_BOOTLOADER = "bootloader"
|
||||
|
||||
@@ -3,19 +3,19 @@ package constants
|
||||
// 令牌常量信息
|
||||
|
||||
// HEADER_PREFIX 令牌-请求头标识前缀
|
||||
const HEADER_PREFIX = "Bearer "
|
||||
const HEADER_PREFIX = "Bearer"
|
||||
|
||||
// HEADER_KEY 令牌-请求头标识
|
||||
const HEADER_KEY = "Authorization"
|
||||
|
||||
// JWT_UUID 令牌-JWT唯一标识字段
|
||||
const JWT_UUID = "uuid"
|
||||
// JWT_DEVICE_ID 令牌-JWT设备标识字段
|
||||
const JWT_DEVICE_ID = "device_id"
|
||||
|
||||
// JWT_USER_ID 令牌-JWT标识用户主键字段
|
||||
const JWT_USER_ID = "user_id"
|
||||
|
||||
// JWT_USER_NAME 令牌-JWT标识用户登录账号字段
|
||||
const JWT_USER_NAME = "user_name"
|
||||
// JWT_CLIENT_ID 令牌-JWT标识客户端ID字段
|
||||
const JWT_CLIENT_ID = "client_id"
|
||||
|
||||
// NMS北向使用-数据响应字段和请求头授权
|
||||
const ACCESS_TOKEN = "accessToken"
|
||||
|
||||
@@ -96,8 +96,8 @@ func (jl *jobLogData) SaveLog(statusFlag string) {
|
||||
"message": jl.Result,
|
||||
})
|
||||
jobMsg := string(jsonByte)
|
||||
if len(jobMsg) > 500 {
|
||||
jobMsg = jobMsg[:500]
|
||||
if len(jobMsg) > 2000 {
|
||||
jobMsg = jobMsg[:2000]
|
||||
}
|
||||
|
||||
// 创建日志对象
|
||||
|
||||
@@ -89,7 +89,8 @@ func Connect() {
|
||||
// 创建连接
|
||||
db, err := gorm.Open(info.dialectic, opts)
|
||||
if err != nil {
|
||||
logger.Fatalf("failed error db connect: %s", err)
|
||||
logger.Errorf("failed error db connect: %s", err)
|
||||
continue
|
||||
}
|
||||
// 获取底层 SQL 数据库连接
|
||||
sqlDB, err := db.DB()
|
||||
@@ -135,7 +136,7 @@ func DB(source string) *gorm.DB {
|
||||
}
|
||||
db := dbMap[source]
|
||||
if db == nil {
|
||||
logger.Fatalf("not database source: %s", source)
|
||||
logger.Errorf("not database source: %s", source)
|
||||
return nil
|
||||
}
|
||||
return db
|
||||
|
||||
@@ -60,8 +60,8 @@ func ImportSQL() {
|
||||
processSQLFile(db, sqlPath)
|
||||
}
|
||||
|
||||
log.Println("Import SQL End")
|
||||
os.Exit(1)
|
||||
log.Println("process success")
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
// 处理单个SQL文件的通用函数
|
||||
|
||||
@@ -16,6 +16,21 @@ import (
|
||||
// Redis连接实例
|
||||
var rdbMap = make(map[string]*redis.Client)
|
||||
|
||||
// 声明定义限流脚本命令
|
||||
var rateLimitCommand = redis.NewScript(`
|
||||
local key = KEYS[1]
|
||||
local time = tonumber(ARGV[1])
|
||||
local count = tonumber(ARGV[2])
|
||||
local current = redis.call('get', key);
|
||||
if current and tonumber(current) >= count then
|
||||
return tonumber(current);
|
||||
end
|
||||
current = redis.call('incr', key)
|
||||
if tonumber(current) == 1 then
|
||||
redis.call('expire', key, time)
|
||||
end
|
||||
return tonumber(current);`)
|
||||
|
||||
// Connect 连接Redis实例
|
||||
func Connect() {
|
||||
ctx := context.Background()
|
||||
@@ -33,7 +48,7 @@ func Connect() {
|
||||
// 测试数据库连接
|
||||
pong, err := rdb.Ping(ctx).Result()
|
||||
if err != nil {
|
||||
logger.Fatalf("failed error redis connect: %s is %v", k, err)
|
||||
logger.Fatalf("Ping redis %s is %v", k, err)
|
||||
}
|
||||
logger.Infof("redis %s %d %s connection is successful.", k, client["db"].(int), pong)
|
||||
rdbMap[k] = rdb
|
||||
@@ -139,6 +154,39 @@ func CommandStats(source string) []map[string]string {
|
||||
return statsObjArr
|
||||
}
|
||||
|
||||
// Has 判断是否存在
|
||||
func Has(source string, keys ...string) (int64, error) {
|
||||
// 数据源
|
||||
rdb := RDB(source)
|
||||
if rdb == nil {
|
||||
return 0, fmt.Errorf("redis not client")
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
exists, err := rdb.Exists(ctx, keys...).Result()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return exists, nil
|
||||
}
|
||||
|
||||
// SetExpire 设置过期时间
|
||||
func SetExpire(source, key string, expiration time.Duration) error {
|
||||
// 数据源
|
||||
rdb := RDB(source)
|
||||
if rdb == nil {
|
||||
return fmt.Errorf("redis not client")
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
err := rdb.Expire(ctx, key, expiration).Err()
|
||||
if err != nil {
|
||||
logger.Errorf("redis Expire err %v", err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetExpire 获取键的剩余有效时间(秒)
|
||||
func GetExpire(source string, key string) (int64, error) {
|
||||
// 数据源
|
||||
@@ -227,41 +275,8 @@ func Get(source, key string) (string, error) {
|
||||
return v, nil
|
||||
}
|
||||
|
||||
// Has 判断是否存在
|
||||
func Has(source string, keys ...string) (int64, error) {
|
||||
// 数据源
|
||||
rdb := RDB(source)
|
||||
if rdb == nil {
|
||||
return 0, fmt.Errorf("redis not client")
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
exists, err := rdb.Exists(ctx, keys...).Result()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return exists, nil
|
||||
}
|
||||
|
||||
// Set 设置缓存数据
|
||||
func Set(source, key string, value any) error {
|
||||
// 数据源
|
||||
rdb := RDB(source)
|
||||
if rdb == nil {
|
||||
return fmt.Errorf("redis not client")
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
err := rdb.Set(ctx, key, value, 0).Err()
|
||||
if err != nil {
|
||||
logger.Errorf("redis Set err %v", err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetByExpire 设置缓存数据与过期时间
|
||||
func SetByExpire(source, key string, value any, expiration time.Duration) error {
|
||||
func Set(source, key string, value any, expiration time.Duration) error {
|
||||
// 数据源
|
||||
rdb := RDB(source)
|
||||
if rdb == nil {
|
||||
@@ -271,7 +286,7 @@ func SetByExpire(source, key string, value any, expiration time.Duration) error
|
||||
ctx := context.Background()
|
||||
err := rdb.Set(ctx, key, value, expiration).Err()
|
||||
if err != nil {
|
||||
logger.Errorf("redis SetByExpire err %v", err)
|
||||
logger.Errorf("redis Set err %v", err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
@@ -329,18 +344,3 @@ func RateLimit(source, limitKey string, time, count int64) (int64, error) {
|
||||
}
|
||||
return result.(int64), err
|
||||
}
|
||||
|
||||
// 声明定义限流脚本命令
|
||||
var rateLimitCommand = redis.NewScript(`
|
||||
local key = KEYS[1]
|
||||
local time = tonumber(ARGV[1])
|
||||
local count = tonumber(ARGV[2])
|
||||
local current = redis.call('get', key);
|
||||
if current and tonumber(current) >= count then
|
||||
return tonumber(current);
|
||||
end
|
||||
current = redis.call('incr', key)
|
||||
if tonumber(current) == 1 then
|
||||
redis.call('expire', key, time)
|
||||
end
|
||||
return tonumber(current);`)
|
||||
|
||||
@@ -20,14 +20,14 @@ func ErrorCatch() gin.HandlerFunc {
|
||||
|
||||
// 返回错误响应给客户端
|
||||
if config.Env() == "prod" {
|
||||
c.JSON(500, resp.CodeMsg(500, "Internal Server Errors"))
|
||||
c.JSON(500, resp.CodeMsg(500001, "Internal Server Errors"))
|
||||
} else {
|
||||
// 通过实现 error 接口的 Error() 方法自定义错误类型进行捕获
|
||||
switch v := err.(type) {
|
||||
case error:
|
||||
c.JSON(500, resp.CodeMsg(500, v.Error()))
|
||||
c.JSON(500, resp.CodeMsg(500001, v.Error()))
|
||||
default:
|
||||
c.JSON(500, resp.CodeMsg(500, fmt.Sprint(err)))
|
||||
c.JSON(500, resp.CodeMsg(500001, fmt.Sprint(err)))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
66
src/framework/middleware/authorize_oauth2.go
Normal file
66
src/framework/middleware/authorize_oauth2.go
Normal file
@@ -0,0 +1,66 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"be.ems/src/framework/constants"
|
||||
"be.ems/src/framework/reqctx"
|
||||
"be.ems/src/framework/resp"
|
||||
"be.ems/src/framework/token"
|
||||
)
|
||||
|
||||
// AuthorizeOauth2 客户端授权认证校验
|
||||
//
|
||||
// scope 客户端授权范围,例如:[]string{"read","write"}
|
||||
func AuthorizeOauth2(scope []string) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
// 获取请求头标识信息
|
||||
tokenStr := reqctx.Authorization(c)
|
||||
if tokenStr == "" {
|
||||
c.JSON(401, resp.CodeMsg(401003, "authorization token is empty"))
|
||||
c.Abort() // 停止执行后续的处理函数
|
||||
return
|
||||
}
|
||||
|
||||
// 验证令牌
|
||||
claims, err := token.Oauth2TokenVerify(tokenStr, "access")
|
||||
if err != nil {
|
||||
c.JSON(401, resp.CodeMsg(401001, err.Error()))
|
||||
c.Abort() // 停止执行后续的处理函数
|
||||
return
|
||||
}
|
||||
|
||||
// 获取缓存的用户信息
|
||||
info := token.Oauth2InfoGet(claims)
|
||||
if info.ClientId == "" {
|
||||
c.JSON(401, resp.CodeMsg(401002, "invalid login user information"))
|
||||
c.Abort() // 停止执行后续的处理函数
|
||||
return
|
||||
}
|
||||
c.Set(constants.CTX_LOGIN_OAUTH2, info)
|
||||
|
||||
// 客户端权限校验
|
||||
if scope != nil {
|
||||
var hasScope bool = false
|
||||
for _, item := range info.Scope {
|
||||
for _, v := range scope {
|
||||
if item == v {
|
||||
hasScope = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if !hasScope {
|
||||
msg := fmt.Sprintf("unauthorized access %s %s", c.Request.Method, c.Request.RequestURI)
|
||||
c.JSON(403, resp.CodeMsg(403001, msg))
|
||||
c.Abort() // 停止执行后续的处理函数
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 调用下一个处理程序
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,17 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"be.ems/src/framework/config"
|
||||
"be.ems/src/framework/constants"
|
||||
"be.ems/src/framework/i18n"
|
||||
"be.ems/src/framework/reqctx"
|
||||
"be.ems/src/framework/resp"
|
||||
"be.ems/src/framework/token"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"be.ems/src/framework/utils/parse"
|
||||
)
|
||||
|
||||
/**无Token可访问白名单 */
|
||||
@@ -26,7 +27,7 @@ var URL_WHITE_LIST = []string{
|
||||
"/oauth/token",
|
||||
}
|
||||
|
||||
// PreAuthorize 用户身份授权认证校验
|
||||
// AuthorizeUser 用户身份授权认证校验
|
||||
//
|
||||
// 只需含有其中角色 "hasRoles": {"xxx"},
|
||||
//
|
||||
@@ -35,13 +36,10 @@ var URL_WHITE_LIST = []string{
|
||||
// 同时匹配其中角色 "matchRoles": {"xxx"},
|
||||
//
|
||||
// 同时匹配其中权限 "matchPerms": {"xxx"},
|
||||
func PreAuthorize(options map[string][]string) gin.HandlerFunc {
|
||||
func AuthorizeUser(options map[string][]string) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
// 登录认证,默认打开
|
||||
enable := true
|
||||
if v := config.Get("user.loginAuth"); v != nil {
|
||||
enable = v.(bool)
|
||||
}
|
||||
enable := parse.Boolean(config.Get("serverLoginAuth"))
|
||||
if !enable {
|
||||
loginUser, _ := reqctx.LoginUser(c)
|
||||
loginUser.UserId = 2
|
||||
@@ -53,12 +51,9 @@ func PreAuthorize(options map[string][]string) gin.HandlerFunc {
|
||||
return
|
||||
}
|
||||
|
||||
language := reqctx.AcceptLanguage(c)
|
||||
|
||||
requestURI := c.Request.RequestURI
|
||||
|
||||
// 判断白名单
|
||||
isWhite := false
|
||||
requestURI := c.Request.RequestURI
|
||||
for _, w := range URL_WHITE_LIST {
|
||||
if strings.Contains(requestURI, w) {
|
||||
isWhite = true
|
||||
@@ -73,42 +68,39 @@ func PreAuthorize(options map[string][]string) gin.HandlerFunc {
|
||||
// 获取请求头标识信息
|
||||
tokenStr := reqctx.Authorization(c)
|
||||
if tokenStr == "" {
|
||||
c.JSON(401, resp.CodeMsg(401, i18n.TKey(language, "app.common.err401")))
|
||||
c.JSON(401, resp.CodeMsg(401003, "authorization token is empty"))
|
||||
c.Abort() // 停止执行后续的处理函数
|
||||
return
|
||||
}
|
||||
|
||||
// 验证令牌
|
||||
claims, err := token.Verify(tokenStr)
|
||||
claims, err := token.UserTokenVerify(tokenStr, "access")
|
||||
if err != nil {
|
||||
c.JSON(401, resp.CodeMsg(401, err.Error()))
|
||||
c.JSON(401, resp.CodeMsg(401001, err.Error()))
|
||||
c.Abort() // 停止执行后续的处理函数
|
||||
return
|
||||
}
|
||||
|
||||
// 获取缓存的用户信息
|
||||
loginUser := token.Info(claims)
|
||||
if loginUser.UserId <= 0 {
|
||||
c.JSON(401, resp.CodeMsg(401, i18n.TKey(language, "app.common.err401")))
|
||||
info := token.UserInfoGet(claims)
|
||||
if info.UserId <= 0 {
|
||||
c.JSON(401, resp.CodeMsg(401002, "invalid login user information"))
|
||||
c.Abort() // 停止执行后续的处理函数
|
||||
return
|
||||
}
|
||||
|
||||
// 检查刷新有效期后存入上下文
|
||||
token.RefreshIn(&loginUser)
|
||||
c.Set(constants.CTX_LOGIN_USER, loginUser)
|
||||
c.Set(constants.CTX_LOGIN_USER, info)
|
||||
|
||||
// 登录用户角色权限校验
|
||||
if options != nil {
|
||||
var roles []string
|
||||
for _, item := range loginUser.User.Roles {
|
||||
for _, item := range info.User.Roles {
|
||||
roles = append(roles, item.RoleKey)
|
||||
}
|
||||
perms := loginUser.Permissions
|
||||
perms := info.Permissions
|
||||
verifyOk := verifyRolePermission(roles, perms, options)
|
||||
if !verifyOk {
|
||||
msg := i18n.TTemplate(language, "app.common.err403", map[string]any{"method": c.Request.Method, "requestURI": requestURI})
|
||||
c.JSON(403, resp.CodeMsg(403, msg))
|
||||
msg := fmt.Sprintf("unauthorized access %s %s", c.Request.Method, c.Request.RequestURI)
|
||||
c.JSON(403, resp.CodeMsg(403001, msg))
|
||||
c.Abort() // 停止执行后续的处理函数
|
||||
return
|
||||
}
|
||||
@@ -127,7 +119,7 @@ func PreAuthorize(options map[string][]string) gin.HandlerFunc {
|
||||
//
|
||||
// options 参数
|
||||
func verifyRolePermission(roles, perms []string, options map[string][]string) bool {
|
||||
// 直接放行 管理员角色或任意权限
|
||||
// 直接放行 系统管理员角色或任意权限
|
||||
if contains(roles, constants.SYS_ROLE_SYSTEM_KEY) || contains(perms, constants.SYS_PERMISSION_SYSTEM) {
|
||||
return true
|
||||
}
|
||||
@@ -103,7 +103,7 @@ func OperateLog(options Options) gin.HandlerFunc {
|
||||
// 获取登录用户信息
|
||||
loginUser, err := reqctx.LoginUser(c)
|
||||
if err != nil {
|
||||
c.JSON(401, resp.CodeMsg(401, i18n.TKey(language, err.Error())))
|
||||
c.JSON(401, resp.CodeMsg(401002, i18n.TKey(language, err.Error())))
|
||||
c.Abort() // 停止执行后续的处理函数
|
||||
return
|
||||
}
|
||||
|
||||
@@ -26,10 +26,7 @@ import (
|
||||
func CryptoApi(requestDecrypt, responseEncrypt bool) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
// 登录认证,默认打开
|
||||
enable := true
|
||||
if v := config.Get("user.cryptoApi"); v != nil && enable {
|
||||
enable = v.(bool)
|
||||
}
|
||||
enable := parse.Boolean(config.Get("serverCryptoApi"))
|
||||
if !enable {
|
||||
c.Next()
|
||||
return
|
||||
@@ -54,7 +51,7 @@ func CryptoApi(requestDecrypt, responseEncrypt bool) gin.HandlerFunc {
|
||||
|
||||
// 是否存在data字段数据
|
||||
if contentDe == "" {
|
||||
c.JSON(400, resp.ErrMsg("decrypt not found field data"))
|
||||
c.JSON(422, resp.CodeMsg(422002, "decrypt not found field data"))
|
||||
c.Abort() // 停止执行后续的处理函数
|
||||
return
|
||||
}
|
||||
@@ -64,7 +61,7 @@ func CryptoApi(requestDecrypt, responseEncrypt bool) gin.HandlerFunc {
|
||||
dataBodyStr, err := crypto.AESDecryptBase64(contentDe, apiKey)
|
||||
if err != nil {
|
||||
logger.Errorf("CryptoApi decrypt err => %v", err)
|
||||
c.JSON(400, resp.ErrMsg("decrypted data could not be parsed"))
|
||||
c.JSON(422, resp.CodeMsg(422001, "decrypted data could not be parsed"))
|
||||
c.Abort() // 停止执行后续的处理函数
|
||||
return
|
||||
}
|
||||
|
||||
@@ -88,7 +88,7 @@ func OperateLog(options Options) gin.HandlerFunc {
|
||||
// 获取登录用户信息
|
||||
loginUser, err := reqctx.LoginUser(c)
|
||||
if err != nil {
|
||||
c.JSON(401, resp.CodeMsg(401, "无效身份授权"))
|
||||
c.JSON(401, resp.CodeMsg(401002, "invalid login user information"))
|
||||
c.Abort() // 停止执行后续的处理函数
|
||||
return
|
||||
}
|
||||
@@ -134,7 +134,7 @@ func OperateLog(options Options) gin.HandlerFunc {
|
||||
contentDisposition := c.Writer.Header().Get("Content-Disposition")
|
||||
contentType := c.Writer.Header().Get("Content-Type")
|
||||
content := contentType + contentDisposition
|
||||
msg := fmt.Sprintf(`{"status":"%d","size":"%d","content-type":"%s"}`, status, c.Writer.Size(), content)
|
||||
msg := fmt.Sprintf(`{"status":"%d","size":%d,"content-type":"%s"}`, status, c.Writer.Size(), content)
|
||||
operaLog.OperaMsg = msg
|
||||
}
|
||||
|
||||
|
||||
@@ -64,7 +64,7 @@ func RateLimit(option LimitOption) gin.HandlerFunc {
|
||||
if option.Type == LIMIT_USER {
|
||||
loginUser, err := reqctx.LoginUser(c)
|
||||
if err != nil {
|
||||
c.JSON(401, resp.CodeMsg(40003, err.Error()))
|
||||
c.JSON(401, resp.CodeMsg(401002, "invalid login user information"))
|
||||
c.Abort() // 停止执行后续的处理函数
|
||||
return
|
||||
}
|
||||
@@ -80,13 +80,13 @@ func RateLimit(option LimitOption) gin.HandlerFunc {
|
||||
// 在Redis查询并记录请求次数
|
||||
rateCount, err := redis.RateLimit("", limitKey, option.Time, option.Count)
|
||||
if err != nil {
|
||||
c.JSON(200, resp.CodeMsg(4013, "访问过于频繁,请稍候再试"))
|
||||
c.JSON(200, resp.ErrMsg("access too often, please try again later"))
|
||||
c.Abort() // 停止执行后续的处理函数
|
||||
return
|
||||
}
|
||||
rateTime, err := redis.GetExpire("", limitKey)
|
||||
if err != nil {
|
||||
c.JSON(200, resp.CodeMsg(4013, "访问过于频繁,请稍候再试"))
|
||||
c.JSON(200, resp.ErrMsg("access too often, please try again later"))
|
||||
c.Abort() // 停止执行后续的处理函数
|
||||
return
|
||||
}
|
||||
@@ -97,7 +97,7 @@ func RateLimit(option LimitOption) gin.HandlerFunc {
|
||||
c.Header("X-RateLimit-Reset", fmt.Sprintf("%d", time.Now().Unix()+rateTime)) // 重置时间戳
|
||||
|
||||
if rateCount >= option.Count {
|
||||
c.JSON(200, resp.CodeMsg(4013, "访问过于频繁,请稍候再试"))
|
||||
c.JSON(200, resp.ErrMsg("access too often, please try again later"))
|
||||
c.Abort() // 停止执行后续的处理函数
|
||||
return
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@ func RepeatSubmit(interval int64) gin.HandlerFunc {
|
||||
logger.Errorf("RepeatSubmit rp json marshal err: %v", err)
|
||||
}
|
||||
// 保存请求时间和参数
|
||||
redis.SetByExpire("", repeatKey, string(rpJSON), time.Duration(interval)*time.Second)
|
||||
redis.Set("", repeatKey, string(rpJSON), time.Duration(interval)*time.Second)
|
||||
|
||||
// 调用下一个处理程序
|
||||
c.Next()
|
||||
|
||||
@@ -60,7 +60,7 @@ func RepeatSubmit(interval int64) gin.HandlerFunc {
|
||||
|
||||
// 小于间隔时间且参数内容一致
|
||||
if compareTime < interval && compareParams {
|
||||
c.JSON(200, resp.ErrMsg("不允许重复提交,请稍候再试"))
|
||||
c.JSON(200, resp.ErrMsg("repeat submissions are not allowed. Please try again later."))
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
@@ -76,7 +76,7 @@ func RepeatSubmit(interval int64) gin.HandlerFunc {
|
||||
logger.Errorf("RepeatSubmit rp json marshal err: %v", err)
|
||||
}
|
||||
// 保存请求时间和参数
|
||||
_ = redis.SetByExpire("", repeatKey, string(rpJSON), time.Duration(interval)*time.Second)
|
||||
_ = redis.Set("", repeatKey, string(rpJSON), time.Duration(interval)*time.Second)
|
||||
|
||||
// 调用下一个处理程序
|
||||
c.Next()
|
||||
|
||||
@@ -12,12 +12,12 @@ import (
|
||||
)
|
||||
|
||||
// LoginUser 登录用户信息
|
||||
func LoginUser(c *gin.Context) (token.TokenInfo, error) {
|
||||
func LoginUser(c *gin.Context) (token.UserInfo, error) {
|
||||
value, exists := c.Get(constants.CTX_LOGIN_USER)
|
||||
if exists && value != nil {
|
||||
return value.(token.TokenInfo), nil
|
||||
return value.(token.UserInfo), nil
|
||||
}
|
||||
return token.TokenInfo{}, fmt.Errorf("invalid login user information")
|
||||
return token.UserInfo{}, fmt.Errorf("invalid login user information")
|
||||
}
|
||||
|
||||
// LoginUserToUserID 登录用户信息-用户ID
|
||||
@@ -58,14 +58,14 @@ func LoginUserByContainRoles(c *gin.Context, target string) bool {
|
||||
|
||||
// LoginUserByContainPerms 登录用户信息-包含权限标识
|
||||
func LoginUserByContainPerms(c *gin.Context, target string) bool {
|
||||
loginUser, err := LoginUser(c)
|
||||
info, err := LoginUser(c)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
if config.IsSystemUser(loginUser.UserId) {
|
||||
if config.IsSystemUser(info.UserId) {
|
||||
return true
|
||||
}
|
||||
perms := loginUser.Permissions
|
||||
perms := info.Permissions
|
||||
for _, str := range perms {
|
||||
if str == target {
|
||||
return true
|
||||
|
||||
@@ -73,11 +73,11 @@ func Authorization(c *gin.Context) string {
|
||||
return ""
|
||||
}
|
||||
// 拆分 Authorization 请求头,提取 JWT 令牌部分
|
||||
arr := strings.SplitN(authHeader, constants.HEADER_PREFIX, 2)
|
||||
if len(arr) < 2 {
|
||||
return ""
|
||||
tokenStr := strings.Replace(authHeader, constants.HEADER_PREFIX, "", 1)
|
||||
if len(tokenStr) > 64 {
|
||||
return strings.TrimSpace(tokenStr) // 去除可能存在的空格
|
||||
}
|
||||
return arr[1]
|
||||
return ""
|
||||
}
|
||||
|
||||
// AcceptLanguage 解析客户端接收语言 zh:中文 en: 英文
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
package reqctx
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"be.ems/src/framework/ip2region"
|
||||
"be.ems/src/framework/utils/crypto"
|
||||
"be.ems/src/framework/utils/ua"
|
||||
)
|
||||
|
||||
@@ -33,3 +36,9 @@ func UaOsBrowser(c *gin.Context) (string, string) {
|
||||
}
|
||||
return os, browser
|
||||
}
|
||||
|
||||
// DeviceFingerprint 设备指纹信息
|
||||
func DeviceFingerprint(c *gin.Context, v any) string {
|
||||
str := fmt.Sprintf("%v:%s", v, c.Request.UserAgent())
|
||||
return crypto.SHA256ToBase64(str)
|
||||
}
|
||||
|
||||
@@ -2,17 +2,17 @@ package resp
|
||||
|
||||
const (
|
||||
// CODE_ERROR 响应-code错误失败
|
||||
CODE_ERROR = 0
|
||||
CODE_ERROR = 400001
|
||||
// MSG_ERROR 响应-msg错误失败
|
||||
MSG_ERROR = "error"
|
||||
|
||||
// CODE_SUCCESS 响应-msg正常成功
|
||||
CODE_SUCCESS = 1
|
||||
CODE_SUCCESS = 200001
|
||||
// MSG_SUCCCESS 响应-code正常成功
|
||||
MSG_SUCCCESS = "success"
|
||||
|
||||
// 响应-code加密数据
|
||||
CODE_ENCRYPT = 2
|
||||
CODE_ENCRYPT = 200999
|
||||
// 响应-msg加密数据
|
||||
MSG_ENCRYPT = "encrypt"
|
||||
)
|
||||
@@ -54,8 +54,8 @@ func OkData(data any) Resp {
|
||||
// Err 响应失败结果 map[string]any{}
|
||||
func Err(v map[string]any) map[string]any {
|
||||
args := make(map[string]any)
|
||||
args["code"] = CODE_SUCCESS
|
||||
args["msg"] = MSG_SUCCCESS
|
||||
args["code"] = CODE_ERROR
|
||||
args["msg"] = MSG_ERROR
|
||||
// v合并到args
|
||||
for key, value := range v {
|
||||
args[key] = value
|
||||
|
||||
@@ -16,7 +16,7 @@ type FileListRow struct {
|
||||
LinkCount int64 `json:"linkCount"` // 硬链接数目
|
||||
Owner string `json:"owner"` // 所属用户
|
||||
Group string `json:"group"` // 所属组
|
||||
Size string `json:"size"` // 文件的大小
|
||||
Size int64 `json:"size"` // 文件的大小
|
||||
ModifiedTime int64 `json:"modifiedTime"` // 最后修改时间,单位为秒
|
||||
FileName string `json:"fileName"` // 文件的名称
|
||||
}
|
||||
@@ -34,10 +34,10 @@ func FileList(sshClient *ConnSSH, path, search string) ([]FileListRow, error) {
|
||||
if search != "" {
|
||||
searchStr = search + searchStr
|
||||
}
|
||||
// cd /var/log && find. -maxdepth 1 -name'mme*' -exec ls -lthd --time-style=+%s {} +
|
||||
cmdStr := fmt.Sprintf("cd %s && find . -maxdepth 1 -name '%s' -exec ls -lthd --time-style=+%%s {} +", path, searchStr)
|
||||
// cd /var/log && ls -lthd --time-style=+%s mme*
|
||||
// cmdStr := fmt.Sprintf("cd %s && ls -lthd --time-style=+%%s %s", path, searchStr)
|
||||
// cd /var/log && find. -maxdepth 1 -name'mme*' -exec ls -ltd --time-style=+%s {} +
|
||||
cmdStr := fmt.Sprintf("cd %s && find . -maxdepth 1 -name '%s' -exec ls -ltd --time-style=+%%s {} +", path, searchStr)
|
||||
// cd /var/log && ls -ltd --time-style=+%s mme*
|
||||
// cmdStr := fmt.Sprintf("cd %s && ls -ltd --time-style=+%%s %s", path, searchStr)
|
||||
|
||||
// 是否远程客户端读取
|
||||
if sshClient == nil {
|
||||
@@ -94,7 +94,7 @@ func FileList(sshClient *ConnSSH, path, search string) ([]FileListRow, error) {
|
||||
LinkCount: parse.Number(fields[1]),
|
||||
Owner: fields[2],
|
||||
Group: fields[3],
|
||||
Size: fields[4],
|
||||
Size: parse.Number(fields[4]),
|
||||
ModifiedTime: parse.Number(fields[5]),
|
||||
FileName: fileName,
|
||||
})
|
||||
|
||||
@@ -24,7 +24,7 @@ func ConvertToStr(telnetClient *ConnTelnet, cmd string) (string, error) {
|
||||
return str, nil
|
||||
}
|
||||
|
||||
return "", fmt.Errorf(str)
|
||||
return "", fmt.Errorf("%s", str)
|
||||
}
|
||||
|
||||
// ConvertToMap 转换为map
|
||||
@@ -41,7 +41,7 @@ func ConvertToMap(telnetClient *ConnTelnet, cmd string) (map[string]string, erro
|
||||
if index != -1 {
|
||||
output = output[:index]
|
||||
}
|
||||
return nil, fmt.Errorf(output)
|
||||
return nil, fmt.Errorf("%s", output)
|
||||
}
|
||||
|
||||
// 初始化一个map用于存储拆分后的键值对
|
||||
|
||||
14
src/framework/token/oauth2_info.go
Normal file
14
src/framework/token/oauth2_info.go
Normal file
@@ -0,0 +1,14 @@
|
||||
package token
|
||||
|
||||
// Oauth2Info 第三方客户端令牌信息对象
|
||||
type Oauth2Info struct {
|
||||
DeviceId string `json:"deviceId"` // 用户设备标识
|
||||
ClientId string `json:"clientId"` // 客户端ID
|
||||
LoginTime int64 `json:"loginTime"` // 登录时间时间戳
|
||||
ExpireTime int64 `json:"expireTime"` // 过期时间时间戳
|
||||
LoginIp string `json:"loginIp"` // 登录IP地址 x.x.x.x
|
||||
LoginLocation string `json:"loginLocation"` // 登录地点 xx xx
|
||||
Browser string `json:"browser"` // 浏览器类型
|
||||
OS string `json:"os"` // 操作系统
|
||||
Scope []string `json:"scope"` // 权限列表
|
||||
}
|
||||
167
src/framework/token/oauth2_token.go
Normal file
167
src/framework/token/oauth2_token.go
Normal file
@@ -0,0 +1,167 @@
|
||||
package token
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/golang-jwt/jwt/v5"
|
||||
|
||||
"be.ems/src/framework/config"
|
||||
"be.ems/src/framework/constants"
|
||||
"be.ems/src/framework/database/redis"
|
||||
"be.ems/src/framework/logger"
|
||||
"be.ems/src/framework/utils/parse"
|
||||
)
|
||||
|
||||
// Oauth2TokenCreate 生成令牌
|
||||
// clientId 客户端ID
|
||||
// deviceFingerprint 设备指纹 SHA256
|
||||
// tokenType 令牌类型 access:访问令牌 refresh:刷新令牌
|
||||
func Oauth2TokenCreate(clientId, deviceFingerprint, tokenType string) (string, int64) {
|
||||
// 令牌算法 HS256 HS384 HS512
|
||||
algorithm := config.Get("jwt.algorithm").(string)
|
||||
var method *jwt.SigningMethodHMAC
|
||||
switch algorithm {
|
||||
case "HS512":
|
||||
method = jwt.SigningMethodHS512
|
||||
case "HS384":
|
||||
method = jwt.SigningMethodHS384
|
||||
default: // 包含HS256和其他所有情况
|
||||
method = jwt.SigningMethodHS256
|
||||
}
|
||||
|
||||
// 生成令牌设置密钥
|
||||
secret := fmt.Sprint(config.Get("jwt.secret"))
|
||||
// 设置令牌过期时间
|
||||
now := time.Now()
|
||||
exp := now
|
||||
if tokenType == "access" {
|
||||
expiresIn := time.Duration(parse.Number(config.Get("jwt.expiresIn")))
|
||||
exp = now.Add(expiresIn * time.Minute)
|
||||
secret = "Oauth2_Access:" + secret
|
||||
}
|
||||
if tokenType == "refresh" {
|
||||
refreshIn := time.Duration(parse.Number(config.Get("jwt.refreshIn")))
|
||||
exp = now.Add(refreshIn * time.Minute)
|
||||
secret = "Oauth2_Refresh:" + secret
|
||||
}
|
||||
|
||||
// 生成令牌负荷绑定uuid标识
|
||||
jwtToken := jwt.NewWithClaims(method, jwt.MapClaims{
|
||||
constants.JWT_DEVICE_ID: deviceFingerprint,
|
||||
constants.JWT_CLIENT_ID: clientId,
|
||||
"exp": exp.Unix(), // 过期时间
|
||||
"iat": now.Unix(), // 签发时间
|
||||
"nbf": now.Unix(), // 生效时间
|
||||
})
|
||||
|
||||
tokenStr, err := jwtToken.SignedString([]byte(secret))
|
||||
if err != nil {
|
||||
logger.Infof("jwt sign err : %v", err)
|
||||
return "", 0
|
||||
}
|
||||
expSeconds := int64(exp.Sub(now).Seconds())
|
||||
return tokenStr, expSeconds
|
||||
}
|
||||
|
||||
// Oauth2TokenVerify 校验令牌是否有效
|
||||
// tokenType 令牌类型 access:访问令牌 refresh:刷新令牌
|
||||
func Oauth2TokenVerify(tokenStr, tokenType string) (jwt.MapClaims, error) {
|
||||
jwtToken, err := jwt.Parse(tokenStr, func(jToken *jwt.Token) (any, error) {
|
||||
// 判断加密算法是预期的加密算法
|
||||
if _, ok := jToken.Method.(*jwt.SigningMethodHMAC); ok {
|
||||
secret := config.Get("jwt.secret").(string)
|
||||
if tokenType == "access" {
|
||||
secret = "Oauth2_Access:" + secret
|
||||
}
|
||||
if tokenType == "refresh" {
|
||||
secret = "Oauth2_Refresh:" + secret
|
||||
}
|
||||
return []byte(secret), nil
|
||||
}
|
||||
return nil, jwt.ErrSignatureInvalid
|
||||
})
|
||||
if err != nil {
|
||||
logger.Errorf("Token Verify Err: %v", err)
|
||||
return nil, fmt.Errorf("token invalid")
|
||||
}
|
||||
// 如果解析负荷成功并通过签名校验
|
||||
claims, ok := jwtToken.Claims.(jwt.MapClaims)
|
||||
if ok && jwtToken.Valid {
|
||||
return claims, nil
|
||||
}
|
||||
return nil, fmt.Errorf("token valid error")
|
||||
}
|
||||
|
||||
// Oauth2InfoRemove 清除登录第三方客户端信息
|
||||
func Oauth2InfoRemove(tokenStr string) (string, error) {
|
||||
claims, err := Oauth2TokenVerify(tokenStr, "access")
|
||||
if err != nil {
|
||||
logger.Errorf("token verify err %v", err)
|
||||
return "", err
|
||||
}
|
||||
deviceId, ok := claims[constants.JWT_DEVICE_ID]
|
||||
if ok && deviceId != "" {
|
||||
// 清除缓存KEY
|
||||
tokenKey := constants.CACHE_OAUTH2_DEVICE + ":" + fmt.Sprint(deviceId)
|
||||
return fmt.Sprint(claims[constants.JWT_CLIENT_ID]), redis.Del("", tokenKey)
|
||||
}
|
||||
return "", fmt.Errorf("token invalid")
|
||||
}
|
||||
|
||||
// Oauth2InfoCreate 生成访问第三方客户端信息缓存
|
||||
func Oauth2InfoCreate(info *Oauth2Info, deviceFingerprint string, ilobArr [4]string) {
|
||||
info.DeviceId = deviceFingerprint
|
||||
|
||||
// 设置请求登录客户端
|
||||
info.LoginIp = ilobArr[0]
|
||||
info.LoginLocation = ilobArr[1]
|
||||
info.OS = ilobArr[2]
|
||||
info.Browser = ilobArr[3]
|
||||
|
||||
expiresIn := time.Duration(parse.Number(config.Get("jwt.expiresIn")))
|
||||
now := time.Now()
|
||||
exp := now.Add(expiresIn * time.Minute)
|
||||
info.LoginTime = now.UnixMilli()
|
||||
info.ExpireTime = exp.UnixMilli()
|
||||
// 登录信息标识缓存
|
||||
tokenKey := constants.CACHE_OAUTH2_DEVICE + ":" + info.DeviceId
|
||||
jsonBytes, err := json.Marshal(info)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
_ = redis.Set("", tokenKey, string(jsonBytes), expiresIn*time.Minute)
|
||||
}
|
||||
|
||||
// Oauth2InfoUpdate 更新访问第三方客户端信息缓存
|
||||
func Oauth2InfoUpdate(info Oauth2Info) {
|
||||
// 登录信息标识缓存
|
||||
tokenKey := constants.CACHE_OAUTH2_DEVICE + ":" + info.DeviceId
|
||||
jsonBytes, err := json.Marshal(info)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
expiresIn, _ := redis.GetExpire("", tokenKey)
|
||||
expiration := time.Duration(expiresIn) * time.Second
|
||||
_ = redis.Set("", tokenKey, string(jsonBytes), expiration)
|
||||
}
|
||||
|
||||
// Oauth2InfoGet 缓存的登录第三方客户端信息
|
||||
func Oauth2InfoGet(claims jwt.MapClaims) Oauth2Info {
|
||||
info := Oauth2Info{}
|
||||
deviceId := fmt.Sprint(claims[constants.JWT_DEVICE_ID])
|
||||
tokenKey := constants.CACHE_OAUTH2_DEVICE + ":" + deviceId
|
||||
hasKey, err := redis.Has("", tokenKey)
|
||||
if hasKey > 0 && err == nil {
|
||||
infoStr, err := redis.Get("", tokenKey)
|
||||
if infoStr == "" || err != nil {
|
||||
return info
|
||||
}
|
||||
if err := json.Unmarshal([]byte(infoStr), &info); err != nil {
|
||||
logger.Errorf("info json err : %v", err)
|
||||
return info
|
||||
}
|
||||
}
|
||||
return info
|
||||
}
|
||||
@@ -1,152 +0,0 @@
|
||||
package token
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/golang-jwt/jwt/v5"
|
||||
|
||||
"be.ems/src/framework/config"
|
||||
"be.ems/src/framework/constants"
|
||||
"be.ems/src/framework/database/redis"
|
||||
"be.ems/src/framework/logger"
|
||||
"be.ems/src/framework/utils/generate"
|
||||
)
|
||||
|
||||
// Remove 清除登录用户信息UUID
|
||||
func Remove(token string) string {
|
||||
claims, err := Verify(token)
|
||||
if err != nil {
|
||||
logger.Errorf("token verify err %v", err)
|
||||
return ""
|
||||
}
|
||||
// 清除缓存KEY
|
||||
uuid := claims[constants.JWT_UUID].(string)
|
||||
tokenKey := constants.CACHE_LOGIN_TOKEN + ":" + uuid
|
||||
hasKey, err := redis.Has("", tokenKey)
|
||||
if hasKey > 0 && err == nil {
|
||||
_ = redis.Del("", tokenKey)
|
||||
}
|
||||
return claims[constants.JWT_USER_NAME].(string)
|
||||
}
|
||||
|
||||
// Create 令牌生成
|
||||
func Create(tokenInfo *TokenInfo, ilobArr [4]string) string {
|
||||
// 生成用户唯一token 32位
|
||||
tokenInfo.UUID = generate.Code(32)
|
||||
tokenInfo.LoginTime = time.Now().UnixMilli()
|
||||
|
||||
// 设置请求用户登录客户端
|
||||
tokenInfo.LoginIp = ilobArr[0]
|
||||
tokenInfo.LoginLocation = ilobArr[1]
|
||||
tokenInfo.OS = ilobArr[2]
|
||||
tokenInfo.Browser = ilobArr[3]
|
||||
|
||||
// 设置新登录IP和登录时间
|
||||
tokenInfo.User.LoginIp = tokenInfo.LoginIp
|
||||
tokenInfo.User.LoginTime = tokenInfo.LoginTime
|
||||
|
||||
// 设置用户令牌有效期并存入缓存
|
||||
Cache(tokenInfo)
|
||||
|
||||
// 令牌算法 HS256 HS384 HS512
|
||||
algorithm := config.Get("jwt.algorithm").(string)
|
||||
var method *jwt.SigningMethodHMAC
|
||||
switch algorithm {
|
||||
case "HS512":
|
||||
method = jwt.SigningMethodHS512
|
||||
case "HS384":
|
||||
method = jwt.SigningMethodHS384
|
||||
case "HS256":
|
||||
default:
|
||||
method = jwt.SigningMethodHS256
|
||||
}
|
||||
// 生成令牌负荷绑定uuid标识
|
||||
jwtToken := jwt.NewWithClaims(method, jwt.MapClaims{
|
||||
constants.JWT_UUID: tokenInfo.UUID,
|
||||
constants.JWT_USER_ID: tokenInfo.UserId,
|
||||
constants.JWT_USER_NAME: tokenInfo.User.UserName,
|
||||
"ait": tokenInfo.LoginTime,
|
||||
})
|
||||
|
||||
// 生成令牌设置密钥
|
||||
secret := config.Get("jwt.secret").(string)
|
||||
tokenStr, err := jwtToken.SignedString([]byte(secret))
|
||||
if err != nil {
|
||||
logger.Infof("jwt sign err : %v", err)
|
||||
return ""
|
||||
}
|
||||
return tokenStr
|
||||
}
|
||||
|
||||
// Cache 缓存登录用户信息
|
||||
func Cache(tokenInfo *TokenInfo) {
|
||||
// 计算配置的有效期
|
||||
expTime := config.Get("jwt.expiresIn").(int)
|
||||
expTimestamp := time.Duration(expTime) * time.Minute
|
||||
iatTimestamp := time.Now().UnixMilli()
|
||||
tokenInfo.LoginTime = iatTimestamp
|
||||
tokenInfo.ExpireTime = iatTimestamp + expTimestamp.Milliseconds()
|
||||
tokenInfo.User.Password = ""
|
||||
// 登录信息标识缓存
|
||||
tokenKey := constants.CACHE_LOGIN_TOKEN + ":" + tokenInfo.UUID
|
||||
jsonBytes, err := json.Marshal(tokenInfo)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
_ = redis.SetByExpire("", tokenKey, string(jsonBytes), expTimestamp)
|
||||
}
|
||||
|
||||
// RefreshIn 验证令牌有效期,相差不足xx分钟,自动刷新缓存
|
||||
func RefreshIn(loginUser *TokenInfo) {
|
||||
// 相差不足xx分钟,自动刷新缓存
|
||||
refreshTime := config.Get("jwt.refreshIn").(int)
|
||||
refreshTimestamp := time.Duration(refreshTime) * time.Minute
|
||||
// 过期时间
|
||||
expireTimestamp := loginUser.ExpireTime
|
||||
currentTimestamp := time.Now().UnixMilli()
|
||||
if expireTimestamp-currentTimestamp <= refreshTimestamp.Milliseconds() {
|
||||
Cache(loginUser)
|
||||
}
|
||||
}
|
||||
|
||||
// Verify 校验令牌是否有效
|
||||
func Verify(token string) (jwt.MapClaims, error) {
|
||||
jwtToken, err := jwt.Parse(token, func(jToken *jwt.Token) (any, error) {
|
||||
// 判断加密算法是预期的加密算法
|
||||
if _, ok := jToken.Method.(*jwt.SigningMethodHMAC); ok {
|
||||
secret := config.Get("jwt.secret").(string)
|
||||
return []byte(secret), nil
|
||||
}
|
||||
return nil, jwt.ErrSignatureInvalid
|
||||
})
|
||||
if err != nil {
|
||||
logger.Errorf("Token Verify Err: %v", err)
|
||||
return nil, fmt.Errorf("token invalid")
|
||||
}
|
||||
// 如果解析负荷成功并通过签名校验
|
||||
if claims, ok := jwtToken.Claims.(jwt.MapClaims); ok && jwtToken.Valid {
|
||||
return claims, nil
|
||||
}
|
||||
return nil, fmt.Errorf("token valid error")
|
||||
}
|
||||
|
||||
// Info 缓存的登录用户信息
|
||||
func Info(claims jwt.MapClaims) TokenInfo {
|
||||
tokenInfo := TokenInfo{}
|
||||
uuid := claims[constants.JWT_UUID].(string)
|
||||
tokenKey := constants.CACHE_LOGIN_TOKEN + ":" + uuid
|
||||
hasKey, err := redis.Has("", tokenKey)
|
||||
if hasKey > 0 && err == nil {
|
||||
infoStr, err := redis.Get("", tokenKey)
|
||||
if infoStr == "" || err != nil {
|
||||
return tokenInfo
|
||||
}
|
||||
if err := json.Unmarshal([]byte(infoStr), &tokenInfo); err != nil {
|
||||
logger.Errorf("info json err : %v", err)
|
||||
return tokenInfo
|
||||
}
|
||||
}
|
||||
return tokenInfo
|
||||
}
|
||||
@@ -2,9 +2,9 @@ package token
|
||||
|
||||
import systemModel "be.ems/src/modules/system/model"
|
||||
|
||||
// TokenInfo 令牌信息对象
|
||||
type TokenInfo struct {
|
||||
UUID string `json:"uuid"` // 用户唯一标识
|
||||
// UserInfo 系统用户令牌信息对象
|
||||
type UserInfo struct {
|
||||
DeviceId string `json:"deviceId"` // 用户设备标识
|
||||
UserId int64 `json:"userId"` // 用户ID
|
||||
DeptId int64 `json:"deptId"` // 部门ID
|
||||
LoginTime int64 `json:"loginTime"` // 登录时间时间戳
|
||||
173
src/framework/token/user_token.go
Normal file
173
src/framework/token/user_token.go
Normal file
@@ -0,0 +1,173 @@
|
||||
package token
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/golang-jwt/jwt/v5"
|
||||
|
||||
"be.ems/src/framework/config"
|
||||
"be.ems/src/framework/constants"
|
||||
"be.ems/src/framework/database/redis"
|
||||
"be.ems/src/framework/logger"
|
||||
"be.ems/src/framework/utils/parse"
|
||||
)
|
||||
|
||||
// UserTokenCreate 生成令牌
|
||||
// userId 用户ID
|
||||
// deviceFingerprint 设备指纹 SHA256
|
||||
// tokenType 令牌类型 access:访问令牌 refresh:刷新令牌
|
||||
func UserTokenCreate(userId int64, deviceFingerprint, tokenType string) (string, int64) {
|
||||
// 令牌算法 HS256 HS384 HS512
|
||||
algorithm := config.Get("jwt.algorithm").(string)
|
||||
var method *jwt.SigningMethodHMAC
|
||||
switch algorithm {
|
||||
case "HS512":
|
||||
method = jwt.SigningMethodHS512
|
||||
case "HS384":
|
||||
method = jwt.SigningMethodHS384
|
||||
default: // 包含HS256和其他所有情况
|
||||
method = jwt.SigningMethodHS256
|
||||
}
|
||||
|
||||
// 生成令牌设置密钥
|
||||
secret := fmt.Sprint(config.Get("jwt.secret"))
|
||||
// 设置令牌过期时间
|
||||
now := time.Now()
|
||||
exp := now
|
||||
if tokenType == "access" {
|
||||
expiresIn := time.Duration(parse.Number(config.Get("jwt.expiresIn")))
|
||||
exp = now.Add(expiresIn * time.Minute)
|
||||
secret = "User_Access:" + secret
|
||||
}
|
||||
if tokenType == "refresh" {
|
||||
refreshIn := time.Duration(parse.Number(config.Get("jwt.refreshIn")))
|
||||
exp = now.Add(refreshIn * time.Minute)
|
||||
secret = "User_Refresh:" + secret
|
||||
}
|
||||
|
||||
// 生成令牌负荷绑定uuid标识
|
||||
jwtToken := jwt.NewWithClaims(method, jwt.MapClaims{
|
||||
constants.JWT_DEVICE_ID: deviceFingerprint,
|
||||
constants.JWT_USER_ID: userId,
|
||||
"exp": exp.Unix(), // 过期时间
|
||||
"iat": now.Unix(), // 签发时间
|
||||
"nbf": now.Add(-10 * time.Second).Unix(), // 生效时间
|
||||
})
|
||||
|
||||
tokenStr, err := jwtToken.SignedString([]byte(secret))
|
||||
if err != nil {
|
||||
logger.Infof("jwt sign err : %v", err)
|
||||
return "", 0
|
||||
}
|
||||
expSeconds := int64(exp.Sub(now).Seconds())
|
||||
return tokenStr, expSeconds
|
||||
}
|
||||
|
||||
// UserTokenVerify 校验令牌是否有效
|
||||
// tokenType 令牌类型 access:访问令牌 refresh:刷新令牌
|
||||
func UserTokenVerify(tokenStr string, tokenType string) (jwt.MapClaims, error) {
|
||||
jwtToken, err := jwt.Parse(tokenStr, func(jToken *jwt.Token) (any, error) {
|
||||
// 判断加密算法是预期的加密算法
|
||||
if _, ok := jToken.Method.(*jwt.SigningMethodHMAC); ok {
|
||||
secret := config.Get("jwt.secret").(string)
|
||||
if tokenType == "access" {
|
||||
secret = "User_Access:" + secret
|
||||
}
|
||||
if tokenType == "refresh" {
|
||||
secret = "User_Refresh:" + secret
|
||||
}
|
||||
return []byte(secret), nil
|
||||
}
|
||||
return nil, jwt.ErrSignatureInvalid
|
||||
})
|
||||
if err != nil {
|
||||
logger.Errorf("Token Verify Err: %v", err)
|
||||
return nil, fmt.Errorf("token invalid")
|
||||
}
|
||||
// 如果解析负荷成功并通过签名校验
|
||||
claims, ok := jwtToken.Claims.(jwt.MapClaims)
|
||||
if ok && jwtToken.Valid {
|
||||
return claims, nil
|
||||
}
|
||||
return nil, fmt.Errorf("token valid error")
|
||||
}
|
||||
|
||||
// UserInfoRemove 清除访问用户信息缓存
|
||||
func UserInfoRemove(tokenStr string) (string, error) {
|
||||
claims, err := UserTokenVerify(tokenStr, "access")
|
||||
if err != nil {
|
||||
logger.Errorf("token verify err %v", err)
|
||||
return "", err
|
||||
}
|
||||
info := UserInfoGet(claims)
|
||||
if info.User.UserName != "" {
|
||||
// 清除缓存KEY
|
||||
deviceId := fmt.Sprint(claims[constants.JWT_DEVICE_ID])
|
||||
tokenKey := constants.CACHE_TOKEN_DEVICE + ":" + deviceId
|
||||
return info.User.UserName, redis.Del("", tokenKey)
|
||||
}
|
||||
return "", fmt.Errorf("token invalid")
|
||||
}
|
||||
|
||||
// UserInfoCreate 生成访问用户信息缓存
|
||||
func UserInfoCreate(info *UserInfo, deviceFingerprint string, ilobArr [4]string) {
|
||||
info.DeviceId = deviceFingerprint
|
||||
|
||||
// 设置请求用户登录客户端
|
||||
info.LoginIp = ilobArr[0]
|
||||
info.LoginLocation = ilobArr[1]
|
||||
info.OS = ilobArr[2]
|
||||
info.Browser = ilobArr[3]
|
||||
|
||||
expiresIn := time.Duration(parse.Number(config.Get("jwt.expiresIn")))
|
||||
now := time.Now()
|
||||
exp := now.Add(expiresIn * time.Minute)
|
||||
info.LoginTime = now.UnixMilli()
|
||||
info.ExpireTime = exp.UnixMilli()
|
||||
// 设置新登录IP和登录时间
|
||||
info.User.LoginIp = info.LoginIp
|
||||
info.User.LoginTime = info.LoginTime
|
||||
info.User.Password = ""
|
||||
// 登录信息标识缓存
|
||||
tokenKey := constants.CACHE_TOKEN_DEVICE + ":" + info.DeviceId
|
||||
jsonBytes, err := json.Marshal(info)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
_ = redis.Set("", tokenKey, string(jsonBytes), expiresIn*time.Minute)
|
||||
}
|
||||
|
||||
// UserInfoUpdate 更新访问用户信息缓存
|
||||
func UserInfoUpdate(info UserInfo) {
|
||||
info.User.Password = ""
|
||||
// 登录信息标识缓存
|
||||
tokenKey := constants.CACHE_TOKEN_DEVICE + ":" + info.DeviceId
|
||||
jsonBytes, err := json.Marshal(info)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
expiresIn, _ := redis.GetExpire("", tokenKey)
|
||||
expiration := time.Duration(expiresIn) * time.Second
|
||||
_ = redis.Set("", tokenKey, string(jsonBytes), expiration)
|
||||
}
|
||||
|
||||
// UserInfoGet 缓存的访问用户信息
|
||||
func UserInfoGet(claims jwt.MapClaims) UserInfo {
|
||||
info := UserInfo{}
|
||||
deviceId := fmt.Sprint(claims[constants.JWT_DEVICE_ID])
|
||||
tokenKey := constants.CACHE_TOKEN_DEVICE + ":" + deviceId
|
||||
hasKey, err := redis.Has("", tokenKey)
|
||||
if hasKey > 0 && err == nil {
|
||||
infoStr, err := redis.Get("", tokenKey)
|
||||
if infoStr == "" || err != nil {
|
||||
return info
|
||||
}
|
||||
if err := json.Unmarshal([]byte(infoStr), &info); err != nil {
|
||||
logger.Errorf("info json err : %v", err)
|
||||
return info
|
||||
}
|
||||
}
|
||||
return info
|
||||
}
|
||||
31
src/framework/utils/crypto/hash.go
Normal file
31
src/framework/utils/crypto/hash.go
Normal file
@@ -0,0 +1,31 @@
|
||||
package crypto
|
||||
|
||||
import (
|
||||
"crypto/hmac"
|
||||
"crypto/md5"
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// SHA256ToBase64 编码字符串
|
||||
func SHA256ToBase64(str string) string {
|
||||
hash := sha256.Sum256([]byte(str))
|
||||
return base64.URLEncoding.EncodeToString(hash[:])
|
||||
}
|
||||
|
||||
// SHA256Hmac HMAC-SHA256算法
|
||||
func SHA256Hmac(key string, data string) string {
|
||||
mac := hmac.New(sha256.New, []byte(key))
|
||||
mac.Write([]byte(data))
|
||||
return hex.EncodeToString(mac.Sum(nil))
|
||||
}
|
||||
|
||||
// MD5 md5加密
|
||||
func MD5(str string) (md5str string) {
|
||||
data := []byte(str)
|
||||
has := md5.Sum(data)
|
||||
md5str = fmt.Sprintf("%x", has)
|
||||
return md5str
|
||||
}
|
||||
@@ -13,11 +13,11 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
libGlobal "be.ems/lib/global"
|
||||
"be.ems/src/framework/config"
|
||||
)
|
||||
|
||||
// userAgent 自定义 User-Agent
|
||||
var userAgent = fmt.Sprintf("OMC/%s", libGlobal.Version)
|
||||
var userAgent = fmt.Sprintf("OMC/%s", config.Version)
|
||||
|
||||
// Get 发送 GET 请求
|
||||
// timeout 超时时间(毫秒)
|
||||
|
||||
78
src/framework/utils/file/files.go
Normal file
78
src/framework/utils/file/files.go
Normal file
@@ -0,0 +1,78 @@
|
||||
package file
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
// FileListRow 文件列表行数据
|
||||
type FileListRow struct {
|
||||
FileType string `json:"fileType"` // 文件类型 dir, file, symlink
|
||||
FileMode string `json:"fileMode"` // 文件的权限
|
||||
LinkCount int64 `json:"linkCount"` // 硬链接数目
|
||||
Owner string `json:"owner"` // 所属用户
|
||||
Group string `json:"group"` // 所属组
|
||||
Size int64 `json:"size"` // 文件的大小
|
||||
ModifiedTime int64 `json:"modifiedTime"` // 最后修改时间,单位为秒
|
||||
FileName string `json:"fileName"` // 文件的名称
|
||||
}
|
||||
|
||||
// 文件列表
|
||||
// search 文件名后模糊*
|
||||
//
|
||||
// return 行记录,异常
|
||||
func FileList(path, search string) ([]FileListRow, error) {
|
||||
var rows []FileListRow
|
||||
|
||||
// 构建搜索模式
|
||||
pattern := "*"
|
||||
if search != "" {
|
||||
pattern = search + pattern
|
||||
}
|
||||
|
||||
// 读取目录内容
|
||||
entries, err := os.ReadDir(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 遍历目录项
|
||||
for _, entry := range entries {
|
||||
// 匹配文件名
|
||||
matched, err := filepath.Match(pattern, entry.Name())
|
||||
if err != nil || !matched {
|
||||
continue
|
||||
}
|
||||
|
||||
// 获取文件详细信息
|
||||
info, err := entry.Info()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
// 确定文件类型
|
||||
fileType := "file"
|
||||
if info.IsDir() {
|
||||
fileType = "dir"
|
||||
} else if info.Mode()&os.ModeSymlink != 0 {
|
||||
fileType = "symlink"
|
||||
}
|
||||
|
||||
// 获取系统特定的文件信息
|
||||
linkCount, owner, group := getFileInfo(info)
|
||||
|
||||
// 组装文件信息
|
||||
rows = append(rows, FileListRow{
|
||||
FileMode: info.Mode().String(),
|
||||
FileType: fileType,
|
||||
LinkCount: linkCount,
|
||||
Owner: owner,
|
||||
Group: group,
|
||||
Size: info.Size(),
|
||||
ModifiedTime: info.ModTime().UnixMilli(),
|
||||
FileName: entry.Name(),
|
||||
})
|
||||
}
|
||||
|
||||
return rows, nil
|
||||
}
|
||||
36
src/framework/utils/file/files_unix.go
Normal file
36
src/framework/utils/file/files_unix.go
Normal file
@@ -0,0 +1,36 @@
|
||||
//go:build !windows
|
||||
// +build !windows
|
||||
|
||||
package file
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/user"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// getFileInfo 获取系统特定的文件信息s
|
||||
func getFileInfo(info os.FileInfo) (linkCount int64, owner, group string) {
|
||||
// Unix-like 系统 (Linux, macOS)
|
||||
if stat, ok := info.Sys().(*syscall.Stat_t); ok {
|
||||
// 获取用户名
|
||||
ownerName := "root"
|
||||
if stat.Uid != 0 {
|
||||
if u, err := user.LookupId(fmt.Sprint(stat.Uid)); err == nil {
|
||||
ownerName = u.Username
|
||||
}
|
||||
}
|
||||
|
||||
// 获取组名
|
||||
groupName := "root"
|
||||
if stat.Gid != 0 {
|
||||
if g, err := user.LookupGroupId(fmt.Sprint(stat.Gid)); err == nil {
|
||||
groupName = g.Name
|
||||
}
|
||||
}
|
||||
|
||||
return int64(stat.Nlink), ownerName, groupName
|
||||
}
|
||||
return 1, "", ""
|
||||
}
|
||||
13
src/framework/utils/file/files_windows.go
Normal file
13
src/framework/utils/file/files_windows.go
Normal file
@@ -0,0 +1,13 @@
|
||||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package file
|
||||
|
||||
import (
|
||||
"os"
|
||||
)
|
||||
|
||||
// getFileInfo 获取系统特定的文件信息
|
||||
func getFileInfo(_ os.FileInfo) (linkCount int64, owner, group string) {
|
||||
return 1, "Administrator", "Administrators"
|
||||
}
|
||||
@@ -163,11 +163,11 @@ func Reset() error {
|
||||
// return fmt.Errorf("not support window")
|
||||
} else {
|
||||
// 重置数据库
|
||||
if _, err := cmd.Execf("sudo cp -rf /usr/local/omc/etc/db/omc_db.sqlite /usr/local/omc/database/omc_db.sqlite"); err != nil {
|
||||
if _, err := cmd.Execf("/usr/local/etc/omc/script/setup.sh -i"); err != nil {
|
||||
return err
|
||||
}
|
||||
// 重启服务
|
||||
if _, err := cmd.Execf("nohup sh -c \"sleep 1s && %s\" > /dev/null 2>&1 &", "sudo systemctl restart restagent"); err != nil {
|
||||
if _, err := cmd.Execf("nohup sh -c \"sleep 1s && %s\" > /dev/null 2>&1 &", "sudo systemctl restart omc"); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
85
src/modules/auth/auth.go
Normal file
85
src/modules/auth/auth.go
Normal file
@@ -0,0 +1,85 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"be.ems/src/framework/logger"
|
||||
"be.ems/src/framework/middleware"
|
||||
"be.ems/src/modules/auth/controller"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// 模块路由注册
|
||||
func Setup(router *gin.Engine) {
|
||||
logger.Infof("开始加载 ====> auth 模块路由")
|
||||
|
||||
// 系统可暴露的配置信息
|
||||
router.GET("/sys-conf", controller.NewSysConf.Handler)
|
||||
|
||||
// 系统引导初始化
|
||||
guideGroup := router.Group("/bootloader")
|
||||
{
|
||||
guideGroup.POST("", controller.NewBootloader.Start)
|
||||
guideGroup.PUT("", middleware.AuthorizeUser(nil), controller.NewBootloader.Done)
|
||||
guideGroup.DELETE("", middleware.AuthorizeUser(nil), controller.NewBootloader.Reset)
|
||||
guideGroup.PUT("/account", middleware.AuthorizeUser(nil), controller.NewBootloader.Account)
|
||||
}
|
||||
|
||||
// 验证码操作
|
||||
router.GET("/captcha-image",
|
||||
middleware.RateLimit(middleware.LimitOption{
|
||||
Time: 300,
|
||||
Count: 60,
|
||||
Type: middleware.LIMIT_IP,
|
||||
}),
|
||||
controller.NewCaptcha.Image,
|
||||
)
|
||||
|
||||
// 账号身份操作
|
||||
{
|
||||
router.POST("/auth/login",
|
||||
middleware.RateLimit(middleware.LimitOption{
|
||||
Time: 180,
|
||||
Count: 15,
|
||||
Type: middleware.LIMIT_IP,
|
||||
}),
|
||||
controller.NewAccount.Login,
|
||||
)
|
||||
router.POST("/auth/logout",
|
||||
middleware.RateLimit(middleware.LimitOption{
|
||||
Time: 120,
|
||||
Count: 15,
|
||||
Type: middleware.LIMIT_IP,
|
||||
}),
|
||||
controller.NewAccount.Logout,
|
||||
)
|
||||
router.POST("/auth/refresh-token",
|
||||
middleware.RateLimit(middleware.LimitOption{
|
||||
Time: 60,
|
||||
Count: 5,
|
||||
Type: middleware.LIMIT_IP,
|
||||
}),
|
||||
controller.NewAccount.RefreshToken,
|
||||
)
|
||||
router.GET("/me",
|
||||
middleware.AuthorizeUser(nil),
|
||||
controller.NewAccount.Me,
|
||||
)
|
||||
router.GET("/router",
|
||||
middleware.AuthorizeUser(nil),
|
||||
controller.NewAccount.Router,
|
||||
)
|
||||
}
|
||||
|
||||
// 账号注册操作
|
||||
{
|
||||
router.POST("/auth/register",
|
||||
middleware.RateLimit(middleware.LimitOption{
|
||||
Time: 300,
|
||||
Count: 10,
|
||||
Type: middleware.LIMIT_IP,
|
||||
}),
|
||||
controller.NewRegister.Register,
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
303
src/modules/auth/controller/account.go
Normal file
303
src/modules/auth/controller/account.go
Normal file
@@ -0,0 +1,303 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"be.ems/src/framework/config"
|
||||
"be.ems/src/framework/constants"
|
||||
"be.ems/src/framework/i18n"
|
||||
"be.ems/src/framework/reqctx"
|
||||
"be.ems/src/framework/resp"
|
||||
"be.ems/src/framework/token"
|
||||
"be.ems/src/framework/utils/parse"
|
||||
"be.ems/src/modules/auth/model"
|
||||
"be.ems/src/modules/auth/service"
|
||||
systemModelVO "be.ems/src/modules/system/model/vo"
|
||||
systemService "be.ems/src/modules/system/service"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// 实例化控制层 AccountController 结构体
|
||||
var NewAccount = &AccountController{
|
||||
accountService: service.NewAccount,
|
||||
sysLogLoginService: systemService.NewSysLogLogin,
|
||||
}
|
||||
|
||||
// 账号身份操作处理
|
||||
//
|
||||
// PATH /
|
||||
type AccountController struct {
|
||||
accountService *service.Account // 账号身份操作服务
|
||||
sysLogLoginService *systemService.SysLogLogin // 系统登录访问
|
||||
}
|
||||
|
||||
// Login 系统登录
|
||||
//
|
||||
// POST /auth/login
|
||||
//
|
||||
// @Tags common/authorization
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param data body object true "Request Param"
|
||||
// @Success 200 {object} object "Response Results"
|
||||
// @Summary System Login
|
||||
// @Description System Login
|
||||
// @Router /auth/login [post]
|
||||
func (s AccountController) Login(c *gin.Context) {
|
||||
language := reqctx.AcceptLanguage(c)
|
||||
var body model.LoginBody
|
||||
if err := c.ShouldBindJSON(&body); err != nil {
|
||||
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||||
c.JSON(422, resp.CodeMsg(422001, errMsgs))
|
||||
return
|
||||
}
|
||||
|
||||
// 当前请求信息
|
||||
ipaddr, location := reqctx.IPAddrLocation(c)
|
||||
os, browser := reqctx.UaOsBrowser(c)
|
||||
|
||||
// 校验验证码 根据错误信息,创建系统访问记录
|
||||
if err := s.accountService.ValidateCaptcha(body.Code, body.UUID); err != nil {
|
||||
msg := fmt.Sprintf("%s code %s", err.Error(), body.Code)
|
||||
s.sysLogLoginService.Insert(
|
||||
body.Username, constants.STATUS_NO, msg,
|
||||
[4]string{ipaddr, location, os, browser},
|
||||
)
|
||||
c.JSON(200, resp.ErrMsg(i18n.TKey(language, err.Error())))
|
||||
return
|
||||
}
|
||||
|
||||
// 登录用户信息
|
||||
info, err := s.accountService.ByUsername(body.Username, body.Password)
|
||||
if err != nil {
|
||||
s.sysLogLoginService.Insert(
|
||||
body.Username, constants.STATUS_NO, err.Error(),
|
||||
[4]string{ipaddr, location, os, browser},
|
||||
)
|
||||
c.JSON(200, resp.ErrMsg(i18n.TKey(language, err.Error())))
|
||||
return
|
||||
}
|
||||
|
||||
data := map[string]any{}
|
||||
|
||||
if !config.IsSystemUser(info.UserId) {
|
||||
// 强制改密码
|
||||
forcePasswdChange, err := s.accountService.PasswordCountOrExpireTime(info.User.LoginCount, info.User.PasswordUpdateTime)
|
||||
if err != nil {
|
||||
c.JSON(200, resp.ErrMsg(i18n.TKey(language, err.Error())))
|
||||
return
|
||||
}
|
||||
if forcePasswdChange {
|
||||
data["forcePasswdChange"] = true
|
||||
}
|
||||
}
|
||||
|
||||
deviceFingerprint := reqctx.DeviceFingerprint(c, info.UserId)
|
||||
|
||||
// 生成访问令牌
|
||||
accessToken, expiresIn := token.UserTokenCreate(info.UserId, deviceFingerprint, "access")
|
||||
if accessToken == "" || expiresIn == 0 {
|
||||
c.JSON(200, resp.ErrMsg("token generation failed"))
|
||||
return
|
||||
}
|
||||
// 生成刷新令牌
|
||||
refreshToken, refreshExpiresIn := token.UserTokenCreate(info.UserId, deviceFingerprint, "refresh")
|
||||
|
||||
// 记录令牌,创建系统访问记录
|
||||
token.UserInfoCreate(&info, deviceFingerprint, [4]string{ipaddr, location, os, browser})
|
||||
s.accountService.UpdateLoginDateAndIP(info)
|
||||
s.sysLogLoginService.Insert(
|
||||
body.Username, constants.STATUS_YES, "app.common.loginSuccess",
|
||||
[4]string{ipaddr, location, os, browser},
|
||||
)
|
||||
|
||||
data["tokenType"] = constants.HEADER_PREFIX
|
||||
data["accessToken"] = accessToken
|
||||
data["expiresIn"] = expiresIn
|
||||
data["refreshToken"] = refreshToken
|
||||
data["refreshExpiresIn"] = refreshExpiresIn
|
||||
data["userId"] = info.UserId
|
||||
c.JSON(200, resp.OkData(data))
|
||||
}
|
||||
|
||||
// Logout 系统登出
|
||||
//
|
||||
// POST /auth/logout
|
||||
func (s AccountController) Logout(c *gin.Context) {
|
||||
language := reqctx.AcceptLanguage(c)
|
||||
tokenStr := reqctx.Authorization(c)
|
||||
if tokenStr != "" {
|
||||
// 存在token时记录退出信息
|
||||
userName, err := token.UserInfoRemove(tokenStr)
|
||||
if err != nil {
|
||||
// 当前请求信息
|
||||
ipaddr, location := reqctx.IPAddrLocation(c)
|
||||
os, browser := reqctx.UaOsBrowser(c)
|
||||
// 创建系统访问记录
|
||||
s.sysLogLoginService.Insert(
|
||||
userName, constants.STATUS_YES, "app.common.logoutSuccess",
|
||||
[4]string{ipaddr, location, os, browser},
|
||||
)
|
||||
}
|
||||
}
|
||||
c.JSON(200, resp.OkMsg(i18n.TKey(language, "app.common.logoutSuccess")))
|
||||
}
|
||||
|
||||
// RefreshToken 刷新Token
|
||||
//
|
||||
// POST /auth/refresh-token
|
||||
func (s AccountController) RefreshToken(c *gin.Context) {
|
||||
var body struct {
|
||||
RefreshToken string `json:"refreshToken" binding:"required"` // 刷新令牌
|
||||
}
|
||||
if err := c.ShouldBindJSON(&body); err != nil {
|
||||
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||||
c.JSON(422, resp.CodeMsg(422001, errMsgs))
|
||||
return
|
||||
}
|
||||
|
||||
// 验证刷新令牌是否有效
|
||||
claims, err := token.UserTokenVerify(body.RefreshToken, "refresh")
|
||||
if err != nil {
|
||||
c.JSON(401, resp.CodeMsg(401001, err.Error()))
|
||||
return
|
||||
}
|
||||
userId := parse.Number(claims[constants.JWT_USER_ID])
|
||||
|
||||
// 登录用户信息
|
||||
info, err := s.accountService.ByUserId(userId)
|
||||
if err != nil {
|
||||
c.JSON(200, resp.ErrMsg(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
// 设备指纹信息是否一致
|
||||
deviceId := fmt.Sprint(claims[constants.JWT_DEVICE_ID])
|
||||
deviceFingerprint := reqctx.DeviceFingerprint(c, userId)
|
||||
if deviceId != deviceFingerprint {
|
||||
c.JSON(200, resp.ErrMsg("device fingerprint mismatch"))
|
||||
return
|
||||
}
|
||||
|
||||
// 生成访问令牌
|
||||
accessToken, expiresIn := token.UserTokenCreate(userId, deviceFingerprint, "access")
|
||||
if accessToken == "" || expiresIn == 0 {
|
||||
c.JSON(200, resp.ErrMsg("token generation failed"))
|
||||
return
|
||||
}
|
||||
// 生成刷新令牌
|
||||
now := time.Now()
|
||||
exp, _ := claims.GetExpirationTime()
|
||||
iat, _ := claims.GetIssuedAt()
|
||||
refreshExpiresIn := int64(exp.Sub(now).Seconds())
|
||||
refreshToken := body.RefreshToken
|
||||
|
||||
// 如果当前时间大于过期时间的一半,则生成新令牌
|
||||
halfExp := exp.Add(-(exp.Sub(iat.Time)) / 2)
|
||||
if now.After(halfExp) {
|
||||
refreshToken, refreshExpiresIn = token.UserTokenCreate(userId, deviceFingerprint, "refresh")
|
||||
}
|
||||
|
||||
// 当前请求信息
|
||||
ipaddr, location := reqctx.IPAddrLocation(c)
|
||||
os, browser := reqctx.UaOsBrowser(c)
|
||||
// 记录令牌,创建系统访问记录
|
||||
token.UserInfoCreate(&info, deviceFingerprint, [4]string{ipaddr, location, os, browser})
|
||||
s.accountService.UpdateLoginDateAndIP(info)
|
||||
s.sysLogLoginService.Insert(
|
||||
info.User.UserName, constants.STATUS_YES, "Refresh Access Token Successful",
|
||||
[4]string{ipaddr, location, os, browser},
|
||||
)
|
||||
|
||||
// 返回访问令牌和刷新令牌
|
||||
c.JSON(200, resp.OkData(map[string]any{
|
||||
"tokenType": constants.HEADER_PREFIX,
|
||||
"accessToken": accessToken,
|
||||
"expiresIn": expiresIn,
|
||||
"refreshToken": refreshToken,
|
||||
"refreshExpiresIn": refreshExpiresIn,
|
||||
"userId": userId,
|
||||
}))
|
||||
}
|
||||
|
||||
// Me 登录用户信息
|
||||
//
|
||||
// GET /me
|
||||
//
|
||||
// @Tags common/authorization
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Success 200 {object} object "Response Results"
|
||||
// @Security TokenAuth
|
||||
// @Summary Login User Information
|
||||
// @Description Login User Information
|
||||
// @Router /me [get]
|
||||
func (s AccountController) Me(c *gin.Context) {
|
||||
language := reqctx.AcceptLanguage(c)
|
||||
info, err := reqctx.LoginUser(c)
|
||||
if err != nil {
|
||||
c.JSON(401, resp.CodeMsg(401002, err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
// 角色权限集合,系统管理员拥有所有权限
|
||||
isSystemUser := config.IsSystemUser(info.UserId)
|
||||
roles, perms := s.accountService.RoleAndMenuPerms(info.UserId, isSystemUser)
|
||||
|
||||
info.User.NickName = i18n.TKey(language, info.User.NickName)
|
||||
info.User.Remark = i18n.TKey(language, info.User.Remark)
|
||||
info.User.Dept.DeptName = i18n.TKey(language, info.User.Dept.DeptName)
|
||||
for ri := range info.User.Roles {
|
||||
info.User.Roles[ri].RoleName = i18n.TKey(language, info.User.Roles[ri].RoleName)
|
||||
}
|
||||
|
||||
data := map[string]any{
|
||||
"user": info.User,
|
||||
"roles": roles,
|
||||
"permissions": perms,
|
||||
}
|
||||
if !isSystemUser {
|
||||
// 强制改密码
|
||||
forcePasswdChange, _ := s.accountService.PasswordCountOrExpireTime(info.User.LoginCount, info.User.PasswordUpdateTime)
|
||||
if forcePasswdChange {
|
||||
data["forcePasswdChange"] = true
|
||||
}
|
||||
}
|
||||
c.JSON(200, resp.OkData(data))
|
||||
}
|
||||
|
||||
// Router 登录用户路由信息
|
||||
//
|
||||
// GET /router
|
||||
//
|
||||
// @Tags common/authorization
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Success 200 {object} object "Response Results"
|
||||
// @Security TokenAuth
|
||||
// @Summary Login User Routing Information
|
||||
// @Description Login User Routing Information
|
||||
// @Router /router [get]
|
||||
func (s AccountController) Router(c *gin.Context) {
|
||||
loginUserId := reqctx.LoginUserToUserID(c)
|
||||
|
||||
// 前端路由,系统管理员拥有所有
|
||||
isSystemUser := config.IsSystemUser(loginUserId)
|
||||
buildMenus := s.accountService.RouteMenus(loginUserId, isSystemUser)
|
||||
// 闭包函数处理多语言
|
||||
language := reqctx.AcceptLanguage(c)
|
||||
var converI18n func(language string, arr *[]systemModelVO.Router)
|
||||
converI18n = func(language string, arr *[]systemModelVO.Router) {
|
||||
for i := range *arr {
|
||||
(*arr)[i].Meta.Title = i18n.TKey(language, (*arr)[i].Meta.Title)
|
||||
if len((*arr)[i].Children) > 0 {
|
||||
converI18n(language, &(*arr)[i].Children)
|
||||
}
|
||||
}
|
||||
}
|
||||
converI18n(language, &buildMenus)
|
||||
|
||||
c.JSON(200, resp.OkData(buildMenus))
|
||||
}
|
||||
@@ -1,18 +1,16 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"be.ems/src/framework/constants"
|
||||
"be.ems/src/framework/i18n"
|
||||
"be.ems/src/framework/reqctx"
|
||||
"be.ems/src/framework/resp"
|
||||
"be.ems/src/framework/token"
|
||||
"be.ems/src/framework/utils/cmd"
|
||||
"be.ems/src/framework/utils/machine"
|
||||
"be.ems/src/framework/utils/regular"
|
||||
"be.ems/src/modules/common/service"
|
||||
"be.ems/src/modules/auth/service"
|
||||
systemService "be.ems/src/modules/system/service"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
@@ -55,7 +53,7 @@ func (s *BootloaderController) Start(c *gin.Context) {
|
||||
}
|
||||
|
||||
// 登录用户信息
|
||||
loginUser := token.TokenInfo{
|
||||
info := token.UserInfo{
|
||||
UserId: sysUser.UserId,
|
||||
DeptId: sysUser.DeptId,
|
||||
User: sysUser,
|
||||
@@ -65,21 +63,26 @@ func (s *BootloaderController) Start(c *gin.Context) {
|
||||
// 当前请求信息
|
||||
ipaddr, location := reqctx.IPAddrLocation(c)
|
||||
os, browser := reqctx.UaOsBrowser(c)
|
||||
deviceFingerprint := reqctx.DeviceFingerprint(c, info.UserId)
|
||||
|
||||
// 生成令牌,创建系统访问记录
|
||||
tokenStr := token.Create(&loginUser, [4]string{ipaddr, location, os, browser})
|
||||
if tokenStr == "" {
|
||||
c.JSON(200, resp.Err(nil))
|
||||
// 生成访问令牌
|
||||
accessToken, expiresIn := token.UserTokenCreate(info.UserId, deviceFingerprint, "access")
|
||||
if accessToken == "" || expiresIn == 0 {
|
||||
c.JSON(200, resp.ErrMsg("token generation failed"))
|
||||
return
|
||||
} else {
|
||||
s.accountService.UpdateLoginDateAndIP(loginUser)
|
||||
}
|
||||
// 记录令牌,创建系统访问记录
|
||||
token.UserInfoCreate(&info, deviceFingerprint, [4]string{ipaddr, location, os, browser})
|
||||
// 创建系统访问记录
|
||||
s.accountService.UpdateLoginDateAndIP(info)
|
||||
|
||||
c.JSON(200, resp.OkData(map[string]any{
|
||||
"accessToken": tokenStr,
|
||||
"tokenType": strings.TrimRight(constants.HEADER_PREFIX, " "),
|
||||
"expiresIn": (loginUser.ExpireTime - loginUser.LoginTime) / 1000,
|
||||
"userId": loginUser.UserId,
|
||||
"tokenType": constants.HEADER_PREFIX,
|
||||
"accessToken": accessToken,
|
||||
"expiresIn": expiresIn,
|
||||
"refreshToken": "",
|
||||
"refreshExpiresIn": 0,
|
||||
"userId": info.UserId,
|
||||
}))
|
||||
}
|
||||
|
||||
@@ -105,7 +108,7 @@ func (s *BootloaderController) Done(c *gin.Context) {
|
||||
}
|
||||
|
||||
// 清除授权信息
|
||||
token.Remove(reqctx.Authorization(c))
|
||||
token.UserInfoRemove(reqctx.Authorization(c))
|
||||
c.JSON(200, resp.Ok(nil))
|
||||
}
|
||||
|
||||
@@ -146,7 +149,7 @@ func (s *BootloaderController) Reset(c *gin.Context) {
|
||||
}
|
||||
|
||||
// 清除授权信息
|
||||
token.Remove(reqctx.Authorization(c))
|
||||
token.UserInfoRemove(reqctx.Authorization(c))
|
||||
c.JSON(200, resp.Ok(nil))
|
||||
}
|
||||
|
||||
@@ -160,15 +163,22 @@ func (s *BootloaderController) Account(c *gin.Context) {
|
||||
Password string `json:"password" binding:"required"`
|
||||
}
|
||||
if err := c.ShouldBindJSON(&body); err != nil {
|
||||
c.JSON(400, resp.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
|
||||
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||||
c.JSON(422, resp.CodeMsg(422001, errMsgs))
|
||||
return
|
||||
}
|
||||
|
||||
if !regular.ValidPassword(body.Password) {
|
||||
// 登录密码至少包含大小写字母、数字、特殊符号,且不少于6位
|
||||
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "user.errPasswd")))
|
||||
// 检查用户密码策略强度
|
||||
ok, errMsg := s.sysUserService.ValidatePasswordPolicy(body.Password, language)
|
||||
if !ok {
|
||||
c.JSON(200, resp.ErrMsg(errMsg))
|
||||
return
|
||||
}
|
||||
// if !regular.ValidPassword(body.Password) {
|
||||
// // 登录密码至少包含大小写字母、数字、特殊符号,且不少于6位
|
||||
// c.JSON(200, resp.ErrMsg(i18n.TKey(language, "user.errPasswd")))
|
||||
// return
|
||||
// }
|
||||
|
||||
// 是否完成引导
|
||||
launchInfo := machine.LaunchInfo
|
||||
@@ -1,8 +1,12 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/mojocn/base64Captcha"
|
||||
|
||||
"be.ems/src/framework/config"
|
||||
"be.ems/src/framework/constants"
|
||||
"be.ems/src/framework/database/redis"
|
||||
@@ -10,42 +14,30 @@ import (
|
||||
"be.ems/src/framework/resp"
|
||||
"be.ems/src/framework/utils/parse"
|
||||
systemService "be.ems/src/modules/system/service"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/mojocn/base64Captcha"
|
||||
)
|
||||
|
||||
// 实例化控制层 CaptchaController 结构体
|
||||
// NewCaptcha 实例化控制层
|
||||
var NewCaptcha = &CaptchaController{
|
||||
sysConfigService: systemService.NewSysConfig,
|
||||
}
|
||||
|
||||
// 验证码操作处理
|
||||
// CaptchaController 验证码操作 控制层处理
|
||||
//
|
||||
// PATH /
|
||||
type CaptchaController struct {
|
||||
sysConfigService *systemService.SysConfig // 参数配置服务
|
||||
}
|
||||
|
||||
// 获取验证码
|
||||
// Image 获取验证码-图片
|
||||
//
|
||||
// GET /captchaImage
|
||||
//
|
||||
// @Tags common
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Success 200 {object} object "Response Results"
|
||||
// @Security TokenAuth
|
||||
// @Summary Get CAPTCHA
|
||||
// @Description Get CAPTCHA
|
||||
// @Router /captchaImage [get]
|
||||
func (s *CaptchaController) Image(c *gin.Context) {
|
||||
// GET /captcha-image
|
||||
func (s CaptchaController) Image(c *gin.Context) {
|
||||
// 从数据库配置获取验证码开关 true开启,false关闭
|
||||
captchaEnabledStr := s.sysConfigService.FindValueByKey("sys.account.captchaEnabled")
|
||||
captchaEnabled := parse.Boolean(captchaEnabledStr)
|
||||
if !captchaEnabled {
|
||||
c.JSON(200, resp.Ok(map[string]any{
|
||||
"captchaEnabled": captchaEnabled,
|
||||
c.JSON(200, resp.OkData(map[string]any{
|
||||
"enabled": captchaEnabled,
|
||||
}))
|
||||
return
|
||||
}
|
||||
@@ -53,14 +45,16 @@ func (s *CaptchaController) Image(c *gin.Context) {
|
||||
// 生成唯一标识
|
||||
verifyKey := ""
|
||||
data := map[string]any{
|
||||
"captchaEnabled": captchaEnabled,
|
||||
"uuid": "",
|
||||
"img": "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7",
|
||||
"enabled": captchaEnabled,
|
||||
"uuid": "",
|
||||
"img": "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7",
|
||||
}
|
||||
|
||||
// 验证码有效期,单位秒
|
||||
captchaExpiration := 2 * 60 * time.Second
|
||||
// 从数据库配置获取验证码类型 math 数值计算 char 字符验证
|
||||
captchaType := s.sysConfigService.FindValueByKey("sys.account.captchaType")
|
||||
if captchaType == constants.CAPTCHA_TYPE_MATH {
|
||||
if captchaType == "math" {
|
||||
math := config.Get("mathCaptcha").(map[string]any)
|
||||
driverCaptcha := &base64Captcha.DriverMath{
|
||||
//Height png height in pixel.
|
||||
@@ -81,16 +75,15 @@ func (s *CaptchaController) Image(c *gin.Context) {
|
||||
// 验证码表达式解析输出
|
||||
item, err := driverCaptcha.DrawCaptcha(question)
|
||||
if err != nil {
|
||||
logger.Infof("Generate Id Question Answer %s %s : %v", captchaType, question, err)
|
||||
logger.Infof("generate id question answer %s %s : %v", captchaType, question, err)
|
||||
} else {
|
||||
data["uuid"] = id
|
||||
data["img"] = item.EncodeB64string()
|
||||
expiration := constants.CAPTCHA_EXPIRATION * time.Second
|
||||
verifyKey = constants.CACHE_CAPTCHA_CODE + ":" + id
|
||||
redis.SetByExpire("", verifyKey, answer, expiration)
|
||||
_ = redis.Set("", verifyKey, answer, captchaExpiration)
|
||||
}
|
||||
}
|
||||
if captchaType == constants.CAPTCHA_TYPE_CHAR {
|
||||
if captchaType == "char" {
|
||||
char := config.Get("charCaptcha").(map[string]any)
|
||||
driverCaptcha := &base64Captcha.DriverString{
|
||||
//Height png height in pixel.
|
||||
@@ -115,13 +108,12 @@ func (s *CaptchaController) Image(c *gin.Context) {
|
||||
// 验证码表达式解析输出
|
||||
item, err := driverCaptcha.DrawCaptcha(question)
|
||||
if err != nil {
|
||||
logger.Infof("Generate Id Question Answer %s %s : %v", captchaType, question, err)
|
||||
logger.Infof("generate id question answer %s %s : %v", captchaType, question, err)
|
||||
} else {
|
||||
data["uuid"] = id
|
||||
data["img"] = item.EncodeB64string()
|
||||
expiration := constants.CAPTCHA_EXPIRATION * time.Second
|
||||
verifyKey = constants.CACHE_CAPTCHA_CODE + ":" + id
|
||||
redis.SetByExpire("", verifyKey, answer, expiration)
|
||||
_ = redis.Set("", verifyKey, strings.ToLower(answer), captchaExpiration)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,8 +121,8 @@ func (s *CaptchaController) Image(c *gin.Context) {
|
||||
if config.Env() == "local" {
|
||||
text, _ := redis.Get("", verifyKey)
|
||||
data["text"] = text
|
||||
c.JSON(200, resp.Ok(data))
|
||||
c.JSON(200, resp.OkData(data))
|
||||
return
|
||||
}
|
||||
c.JSON(200, resp.Ok(data))
|
||||
c.JSON(200, resp.OkData(data))
|
||||
}
|
||||
@@ -8,8 +8,8 @@ import (
|
||||
"be.ems/src/framework/reqctx"
|
||||
"be.ems/src/framework/resp"
|
||||
"be.ems/src/framework/utils/regular"
|
||||
"be.ems/src/modules/common/model"
|
||||
"be.ems/src/modules/common/service"
|
||||
"be.ems/src/modules/auth/model"
|
||||
"be.ems/src/modules/auth/service"
|
||||
systemService "be.ems/src/modules/system/service"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
@@ -29,15 +29,32 @@ type RegisterController struct {
|
||||
sysLogLoginService *systemService.SysLogLogin // 系统登录访问服务
|
||||
}
|
||||
|
||||
// 账号注册
|
||||
// Register 账号注册
|
||||
//
|
||||
// GET /register
|
||||
func (s *RegisterController) Register(c *gin.Context) {
|
||||
// POST /auth/register
|
||||
func (s RegisterController) Register(c *gin.Context) {
|
||||
language := reqctx.AcceptLanguage(c)
|
||||
var body model.RegisterBody
|
||||
if err := c.ShouldBindJSON(&body); err != nil {
|
||||
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||||
c.JSON(422, resp.CodeMsg(40422, errMsgs))
|
||||
c.JSON(422, resp.CodeMsg(422001, errMsgs))
|
||||
return
|
||||
}
|
||||
|
||||
// 当前请求信息
|
||||
ipaddr, location := reqctx.IPAddrLocation(c)
|
||||
os, browser := reqctx.UaOsBrowser(c)
|
||||
|
||||
// 校验验证码
|
||||
err := s.registerService.ValidateCaptcha(body.Code, body.UUID)
|
||||
// 根据错误信息,创建系统访问记录
|
||||
if err != nil {
|
||||
msg := fmt.Sprintf("%s code %s", err.Error(), body.Code)
|
||||
s.sysLogLoginService.Insert(
|
||||
body.Username, constants.STATUS_NO, msg,
|
||||
[4]string{ipaddr, location, os, browser},
|
||||
)
|
||||
c.JSON(200, resp.ErrMsg(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -58,26 +75,7 @@ func (s *RegisterController) Register(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
// 当前请求信息
|
||||
ipaddr, location := reqctx.IPAddrLocation(c)
|
||||
os, browser := reqctx.UaOsBrowser(c)
|
||||
|
||||
// 校验验证码
|
||||
err := s.registerService.ValidateCaptcha(
|
||||
body.Code,
|
||||
body.UUID,
|
||||
)
|
||||
// 根据错误信息,创建系统访问记录
|
||||
if err != nil {
|
||||
msg := err.Error() + " code: " + body.Code
|
||||
s.sysLogLoginService.Insert(
|
||||
body.Username, constants.STATUS_NO, msg,
|
||||
[4]string{ipaddr, location, os, browser},
|
||||
)
|
||||
c.JSON(200, resp.ErrMsg(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
// 进行注册
|
||||
userId, err := s.registerService.ByUserName(body.Username, body.Password)
|
||||
if err == nil {
|
||||
msg := i18n.TTemplate(language, "register.successMsg", map[string]any{"name": body.Username, "id": userId})
|
||||
@@ -1,31 +1,47 @@
|
||||
package service
|
||||
package controller
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"be.ems/lib/global"
|
||||
"be.ems/src/framework/config"
|
||||
"be.ems/src/framework/i18n"
|
||||
"be.ems/src/framework/reqctx"
|
||||
"be.ems/src/framework/resp"
|
||||
systemService "be.ems/src/modules/system/service"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// 实例化服务层 Commont 结构体
|
||||
var NewCommont = &Commont{
|
||||
// 实例化控制层 SysConfController 结构体
|
||||
var NewSysConf = &SysConfController{
|
||||
sysUserService: systemService.NewSysUser,
|
||||
sysConfigService: systemService.NewSysConfig,
|
||||
}
|
||||
|
||||
// 通用请求 服务层处理
|
||||
type Commont struct {
|
||||
// 系统的配置信息
|
||||
//
|
||||
// PATH /sys-conf
|
||||
type SysConfController struct {
|
||||
sysUserService *systemService.SysUser // 用户信息服务
|
||||
sysConfigService *systemService.SysConfig // 参数配置服务
|
||||
}
|
||||
|
||||
// SystemConfigInfo 系统配置信息
|
||||
func (s *Commont) SystemConfigInfo() map[string]string {
|
||||
// 系统的配置信息
|
||||
//
|
||||
// GET /
|
||||
//
|
||||
// @Tags common
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Success 200 {object} object "Response Results"
|
||||
// @Summary Configuration information for the system
|
||||
// @Description Configuration information for the system
|
||||
// @Router /sys-conf [get]
|
||||
func (s SysConfController) Handler(c *gin.Context) {
|
||||
language := reqctx.AcceptLanguage(c)
|
||||
|
||||
infoMap := map[string]string{}
|
||||
// 获取打包注入的全局变量信息
|
||||
infoMap["version"] = global.Version
|
||||
// infoMap["buildTime"] = global.BuildTime
|
||||
infoMap["version"] = config.Version
|
||||
// 系统首次使用标记
|
||||
// launchInfo := machine.LaunchInfo
|
||||
// if launchInfo != nil {
|
||||
@@ -37,10 +53,12 @@ func (s *Commont) SystemConfigInfo() map[string]string {
|
||||
// } else {
|
||||
// infoMap[constants.LAUNCH_BOOTLOADER] = "true"
|
||||
// }
|
||||
// 服务版本
|
||||
infoMap["serverVersion"] = fmt.Sprint(config.Get("serverVersion"))
|
||||
// 用户登录认证
|
||||
infoMap["loginAuth"] = fmt.Sprint(config.Get("user.loginAuth"))
|
||||
infoMap["loginAuth"] = fmt.Sprint(config.Get("serverLoginAuth"))
|
||||
// 用户接口加密
|
||||
infoMap["cryptoApi"] = fmt.Sprint(config.Get("user.cryptoApi"))
|
||||
infoMap["cryptoApi"] = fmt.Sprint(config.Get("serverCryptoApi"))
|
||||
// 序列号
|
||||
infoMap["serialNum"] = fmt.Sprint(config.Get("omc.sn"))
|
||||
// 获取LOGO类型
|
||||
@@ -53,10 +71,10 @@ func (s *Commont) SystemConfigInfo() map[string]string {
|
||||
infoMap["filePathBrand"] = filePathBrand
|
||||
// 获取系统名称
|
||||
title := s.sysConfigService.FindValueByKey("sys.title")
|
||||
infoMap["title"] = title
|
||||
infoMap["title"] = i18n.TKey(language, title)
|
||||
// 获取版权声明
|
||||
copyright := s.sysConfigService.FindValueByKey("sys.copyright")
|
||||
infoMap["copyright"] = copyright
|
||||
infoMap["copyright"] = i18n.TKey(language, copyright)
|
||||
// 获取是否开启用户注册功能
|
||||
registerUser := s.sysConfigService.FindValueByKey("sys.account.registerUser")
|
||||
infoMap["registerUser"] = registerUser
|
||||
@@ -75,5 +93,6 @@ func (s *Commont) SystemConfigInfo() map[string]string {
|
||||
// 国际化默认语言
|
||||
i18nDefault := s.sysConfigService.FindValueByKey("sys.i18n.default")
|
||||
infoMap["i18nDefault"] = i18nDefault
|
||||
return infoMap
|
||||
|
||||
c.JSON(200, resp.OkData(infoMap))
|
||||
}
|
||||
@@ -56,25 +56,25 @@ func (s *Account) ValidateCaptcha(code, uuid string) error {
|
||||
}
|
||||
|
||||
// ByUsername 登录创建用户信息
|
||||
func (s Account) ByUsername(username, password string) (token.TokenInfo, error) {
|
||||
tokenInfo := token.TokenInfo{}
|
||||
func (s Account) ByUsername(username, password string) (token.UserInfo, error) {
|
||||
info := token.UserInfo{}
|
||||
|
||||
// 检查密码重试次数
|
||||
retryKey, retryCount, lockTime, err := s.passwordRetryCount(username)
|
||||
if err != nil {
|
||||
return tokenInfo, err
|
||||
return info, err
|
||||
}
|
||||
|
||||
// 查询用户登录账号
|
||||
sysUser := s.sysUserService.FindByUserName(username)
|
||||
if sysUser.UserName != username {
|
||||
return tokenInfo, fmt.Errorf("login.errNameOrPasswd")
|
||||
return info, fmt.Errorf("login.errNameOrPasswd")
|
||||
}
|
||||
if sysUser.DelFlag == constants.STATUS_YES {
|
||||
return tokenInfo, fmt.Errorf("login.errDelFlag")
|
||||
return info, fmt.Errorf("login.errDelFlag")
|
||||
}
|
||||
if sysUser.StatusFlag == constants.STATUS_NO {
|
||||
return tokenInfo, fmt.Errorf("login.errStatus")
|
||||
return info, fmt.Errorf("login.errStatus")
|
||||
}
|
||||
|
||||
// 检验用户密码
|
||||
@@ -82,30 +82,61 @@ func (s Account) ByUsername(username, password string) (token.TokenInfo, error)
|
||||
if compareBool {
|
||||
s.CleanLoginRecordCache(sysUser.UserName) // 清除错误记录次数
|
||||
} else {
|
||||
_ = redis.SetByExpire("", retryKey, retryCount+1, lockTime)
|
||||
return tokenInfo, fmt.Errorf("login.errNameOrPasswd")
|
||||
_ = redis.Set("", retryKey, retryCount+1, lockTime)
|
||||
return info, fmt.Errorf("login.errNameOrPasswd")
|
||||
}
|
||||
|
||||
// 登录用户信息
|
||||
tokenInfo.UserId = sysUser.UserId
|
||||
tokenInfo.DeptId = sysUser.DeptId
|
||||
tokenInfo.User = sysUser
|
||||
info.UserId = sysUser.UserId
|
||||
info.DeptId = sysUser.DeptId
|
||||
info.User = sysUser
|
||||
// 用户权限组标识
|
||||
if config.IsSystemUser(sysUser.UserId) {
|
||||
tokenInfo.Permissions = []string{constants.SYS_PERMISSION_SYSTEM}
|
||||
info.Permissions = []string{constants.SYS_PERMISSION_SYSTEM}
|
||||
} else {
|
||||
perms := s.sysMenuService.FindPermsByUserId(sysUser.UserId)
|
||||
tokenInfo.Permissions = parse.RemoveDuplicates(perms)
|
||||
info.Permissions = parse.RemoveDuplicates(perms)
|
||||
}
|
||||
return tokenInfo, nil
|
||||
return info, nil
|
||||
}
|
||||
|
||||
// ByUserId 用户ID刷新令牌创建用户信息
|
||||
func (s Account) ByUserId(userId int64) (token.UserInfo, error) {
|
||||
info := token.UserInfo{}
|
||||
|
||||
// 查询用户登录账号
|
||||
sysUser := s.sysUserService.FindById(userId)
|
||||
if sysUser.UserId != userId {
|
||||
return info, fmt.Errorf("user does not exist")
|
||||
}
|
||||
if sysUser.DelFlag == constants.STATUS_YES {
|
||||
return info, fmt.Errorf("sorry, your account has been deleted. Sorry, your account has been deleted")
|
||||
}
|
||||
if sysUser.StatusFlag == constants.STATUS_NO {
|
||||
return info, fmt.Errorf("sorry, your account has been disabled")
|
||||
}
|
||||
|
||||
// 登录用户信息
|
||||
info.UserId = sysUser.UserId
|
||||
info.DeptId = sysUser.DeptId
|
||||
info.User = sysUser
|
||||
// 用户权限组标识
|
||||
if config.IsSystemUser(sysUser.UserId) {
|
||||
info.Permissions = []string{constants.SYS_PERMISSION_SYSTEM}
|
||||
} else {
|
||||
perms := s.sysMenuService.FindPermsByUserId(sysUser.UserId)
|
||||
info.Permissions = parse.RemoveDuplicates(perms)
|
||||
}
|
||||
return info, nil
|
||||
}
|
||||
|
||||
// UpdateLoginDateAndIP 更新登录时间和IP
|
||||
func (s Account) UpdateLoginDateAndIP(tokenInfo token.TokenInfo) bool {
|
||||
user := s.sysUserService.FindById(tokenInfo.UserId)
|
||||
func (s Account) UpdateLoginDateAndIP(info token.UserInfo) bool {
|
||||
user := s.sysUserService.FindById(info.UserId)
|
||||
user.Password = "" // 密码不更新
|
||||
user.LoginIp = tokenInfo.LoginIp
|
||||
user.LoginTime = tokenInfo.LoginTime
|
||||
user.LoginCount += 1
|
||||
user.LoginIp = info.LoginIp
|
||||
user.LoginTime = info.LoginTime
|
||||
return s.sysUserService.Update(user) > 0
|
||||
}
|
||||
|
||||
@@ -127,9 +158,6 @@ func (s Account) passwordRetryCount(userName string) (string, int64, time.Durati
|
||||
// 验证登录次数和错误锁定时间
|
||||
maxRetryCount := parse.Number(maxRetryCountStr)
|
||||
lockTime := parse.Number(lockTimeStr)
|
||||
// 验证登录次数和错误锁定时间
|
||||
// maxRetryCount := config.Get("user.password.maxRetryCount").(int)
|
||||
// lockTime := config.Get("user.password.lockTime").(int)
|
||||
|
||||
// 验证缓存记录次数
|
||||
retryKey := fmt.Sprintf("%s:%s", constants.CACHE_PWD_ERR_COUNT, userName)
|
||||
@@ -147,6 +175,26 @@ func (s Account) passwordRetryCount(userName string) (string, int64, time.Durati
|
||||
return retryKey, retryCountInt64, time.Duration(lockTime) * time.Minute, nil
|
||||
}
|
||||
|
||||
// PasswordCountOrExpireTime 首次登录或密码过期时间
|
||||
func (s Account) PasswordCountOrExpireTime(loginCount, passwordUpdateTime int64) (bool, error) {
|
||||
forcePasswdChange := false
|
||||
// 从数据库配置获取-首次登录密码修改
|
||||
fristPasswdChangeStr := s.sysConfigService.FindValueByKey("sys.user.fristPasswdChange")
|
||||
if parse.Boolean(fristPasswdChangeStr) {
|
||||
forcePasswdChange = loginCount < 1 || passwordUpdateTime == 0
|
||||
}
|
||||
|
||||
// 非首次登录,判断密码是否过期
|
||||
if !forcePasswdChange {
|
||||
alert, err := s.sysUserService.ValidatePasswordExpireTime(passwordUpdateTime)
|
||||
if err != nil {
|
||||
return alert, err
|
||||
}
|
||||
forcePasswdChange = alert
|
||||
}
|
||||
return forcePasswdChange, nil
|
||||
}
|
||||
|
||||
// RoleAndMenuPerms 角色和菜单数据权限
|
||||
func (s Account) RoleAndMenuPerms(userId int64, isSystemUser bool) ([]string, []string) {
|
||||
if isSystemUser {
|
||||
@@ -78,7 +78,7 @@ func (s Register) ByUserName(username, password string) (int64, error) {
|
||||
if insertId > 0 {
|
||||
return insertId, nil
|
||||
}
|
||||
return 0, fmt.Errorf("failed to register user [%s]. Please contact the system administrator", username)
|
||||
return 0, fmt.Errorf("failed to register user [%s]. Please contact the GM", username)
|
||||
}
|
||||
|
||||
// registerRoleInit 注册初始角色
|
||||
@@ -17,20 +17,20 @@ func Setup(router *gin.Engine) {
|
||||
chartGraphGroup := router.Group("/chart/graph")
|
||||
{
|
||||
chartGraphGroup.GET("",
|
||||
middleware.PreAuthorize(nil),
|
||||
middleware.AuthorizeUser(nil),
|
||||
controller.NewChartGraph.Load,
|
||||
)
|
||||
chartGraphGroup.GET("/groups",
|
||||
middleware.PreAuthorize(nil),
|
||||
middleware.AuthorizeUser(nil),
|
||||
controller.NewChartGraph.GroupNames,
|
||||
)
|
||||
chartGraphGroup.POST("",
|
||||
middleware.PreAuthorize(nil),
|
||||
middleware.AuthorizeUser(nil),
|
||||
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.chartGraph", collectlogs.BUSINESS_TYPE_UPDATE)),
|
||||
controller.NewChartGraph.Save,
|
||||
)
|
||||
chartGraphGroup.DELETE("/:group",
|
||||
middleware.PreAuthorize(nil),
|
||||
middleware.AuthorizeUser(nil),
|
||||
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.chartGraph", collectlogs.BUSINESS_TYPE_DELETE)),
|
||||
controller.NewChartGraph.Delete,
|
||||
)
|
||||
|
||||
@@ -3,8 +3,6 @@ package controller
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"be.ems/src/framework/i18n"
|
||||
"be.ems/src/framework/reqctx"
|
||||
"be.ems/src/framework/resp"
|
||||
"be.ems/src/modules/chart/service"
|
||||
|
||||
@@ -62,7 +60,7 @@ func (s *ChartGraphController) Load(c *gin.Context) {
|
||||
}
|
||||
if err := c.ShouldBindQuery(&querys); err != nil {
|
||||
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||||
c.JSON(422, resp.CodeMsg(40422, errMsgs))
|
||||
c.JSON(422, resp.CodeMsg(422001, errMsgs))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -94,7 +92,7 @@ func (s *ChartGraphController) Save(c *gin.Context) {
|
||||
}
|
||||
if err := c.ShouldBindBodyWithJSON(&body); err != nil {
|
||||
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||||
c.JSON(422, resp.CodeMsg(40422, errMsgs))
|
||||
c.JSON(422, resp.CodeMsg(422001, errMsgs))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -125,10 +123,9 @@ func (s *ChartGraphController) Save(c *gin.Context) {
|
||||
// @Description Deleting Relationship Diagram Data
|
||||
// @Router /chart/graph/{group} [delete]
|
||||
func (s *ChartGraphController) Delete(c *gin.Context) {
|
||||
language := reqctx.AcceptLanguage(c)
|
||||
group := c.Param("group")
|
||||
if group == "" {
|
||||
c.JSON(400, resp.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
|
||||
c.JSON(422, resp.CodeMsg(422002, "bind err: group is empty"))
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -22,78 +22,24 @@ func Setup(router *gin.Engine) {
|
||||
controller.NewIndex.Handler,
|
||||
)
|
||||
|
||||
// 系统可暴露的配置信息
|
||||
router.GET("/sys-conf", controller.NewCommon.SysConfig)
|
||||
// 系统引导初始化
|
||||
guideGroup := router.Group("/bootloader")
|
||||
{
|
||||
guideGroup.POST("", controller.NewBootloader.Start)
|
||||
guideGroup.PUT("", middleware.PreAuthorize(nil), controller.NewBootloader.Done)
|
||||
guideGroup.DELETE("", middleware.PreAuthorize(nil), controller.NewBootloader.Reset)
|
||||
guideGroup.PUT("/account", middleware.PreAuthorize(nil), controller.NewBootloader.Account)
|
||||
}
|
||||
|
||||
// 验证码操作
|
||||
router.GET("/captcha-image",
|
||||
middleware.RateLimit(middleware.LimitOption{
|
||||
Time: 300,
|
||||
Count: 60,
|
||||
Type: middleware.LIMIT_IP,
|
||||
}),
|
||||
controller.NewCaptcha.Image,
|
||||
)
|
||||
|
||||
// 账号身份操作处理
|
||||
{
|
||||
router.POST("/login",
|
||||
middleware.RateLimit(middleware.LimitOption{
|
||||
Time: 180,
|
||||
Count: 15,
|
||||
Type: middleware.LIMIT_IP,
|
||||
}),
|
||||
middleware.CryptoApi(true, true),
|
||||
controller.NewAccount.Login,
|
||||
)
|
||||
router.GET("/me", middleware.PreAuthorize(nil), controller.NewAccount.Me)
|
||||
router.GET("/router", middleware.PreAuthorize(nil), controller.NewAccount.Router)
|
||||
router.POST("/logout",
|
||||
middleware.RateLimit(middleware.LimitOption{
|
||||
Time: 120,
|
||||
Count: 15,
|
||||
Type: middleware.LIMIT_IP,
|
||||
}),
|
||||
controller.NewAccount.Logout,
|
||||
)
|
||||
}
|
||||
|
||||
// 账号注册操作
|
||||
{
|
||||
router.POST("/register",
|
||||
middleware.RateLimit(middleware.LimitOption{
|
||||
Time: 300,
|
||||
Count: 10,
|
||||
Type: middleware.LIMIT_IP,
|
||||
}),
|
||||
middleware.CryptoApi(true, true),
|
||||
controller.NewRegister.Register,
|
||||
)
|
||||
}
|
||||
|
||||
// 通用请求
|
||||
commonGroup := router.Group("/common")
|
||||
{
|
||||
commonGroup.POST("/hash", middleware.PreAuthorize(nil), controller.NewCommon.Hash)
|
||||
commonGroup.POST("/hash", middleware.AuthorizeUser(nil), controller.NewCommon.Hash)
|
||||
commonGroup.GET("/i18n", controller.NewCommon.I18n)
|
||||
}
|
||||
|
||||
// 文件操作处理
|
||||
fileGroup := router.Group("/file")
|
||||
{
|
||||
fileGroup.POST("/upload", middleware.PreAuthorize(nil), controller.NewFile.Upload)
|
||||
fileGroup.POST("/chunk-check", middleware.PreAuthorize(nil), controller.NewFile.ChunkCheck)
|
||||
fileGroup.POST("/chunk-upload", middleware.PreAuthorize(nil), controller.NewFile.ChunkUpload)
|
||||
fileGroup.POST("/chunk-merge", middleware.PreAuthorize(nil), controller.NewFile.ChunkMerge)
|
||||
fileGroup.GET("/download/:filePath", middleware.PreAuthorize(nil), controller.NewFile.Download)
|
||||
fileGroup.POST("/transfer-static-file", middleware.PreAuthorize(nil), controller.NewFile.TransferStaticFile)
|
||||
fileGroup.POST("/upload", middleware.AuthorizeUser(nil), controller.NewFile.Upload)
|
||||
fileGroup.POST("/chunk-check", middleware.AuthorizeUser(nil), controller.NewFile.ChunkCheck)
|
||||
fileGroup.POST("/chunk-upload", middleware.AuthorizeUser(nil), controller.NewFile.ChunkUpload)
|
||||
fileGroup.POST("/chunk-merge", middleware.AuthorizeUser(nil), controller.NewFile.ChunkMerge)
|
||||
fileGroup.GET("/download/:filePath", middleware.AuthorizeUser(nil), controller.NewFile.Download)
|
||||
fileGroup.GET("/list", middleware.AuthorizeUser(nil), controller.NewFile.List)
|
||||
fileGroup.GET("", middleware.AuthorizeUser(nil), controller.NewFile.File)
|
||||
fileGroup.DELETE("", middleware.AuthorizeUser(nil), controller.NewFile.Remove)
|
||||
fileGroup.POST("/transfer-static-file", middleware.AuthorizeUser(nil), controller.NewFile.TransferStaticFile)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,203 +0,0 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"be.ems/src/framework/config"
|
||||
"be.ems/src/framework/constants"
|
||||
"be.ems/src/framework/i18n"
|
||||
"be.ems/src/framework/reqctx"
|
||||
"be.ems/src/framework/resp"
|
||||
"be.ems/src/framework/token"
|
||||
"be.ems/src/modules/common/model"
|
||||
"be.ems/src/modules/common/service"
|
||||
systemModelVO "be.ems/src/modules/system/model/vo"
|
||||
systemService "be.ems/src/modules/system/service"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// 实例化控制层 AccountController 结构体
|
||||
var NewAccount = &AccountController{
|
||||
accountService: service.NewAccount,
|
||||
sysLogLoginService: systemService.NewSysLogLogin,
|
||||
}
|
||||
|
||||
// 账号身份操作处理
|
||||
//
|
||||
// PATH /
|
||||
type AccountController struct {
|
||||
accountService *service.Account // 账号身份操作服务
|
||||
sysLogLoginService *systemService.SysLogLogin // 系统登录访问
|
||||
}
|
||||
|
||||
// Login 系统登录
|
||||
//
|
||||
// POST /login
|
||||
//
|
||||
// @Tags common/authorization
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param data body object true "Request Param"
|
||||
// @Success 200 {object} object "Response Results"
|
||||
// @Summary System Login
|
||||
// @Description System Login
|
||||
// @Router /login [post]
|
||||
func (s AccountController) Login(c *gin.Context) {
|
||||
language := reqctx.AcceptLanguage(c)
|
||||
var body model.LoginBody
|
||||
if err := c.ShouldBindJSON(&body); err != nil {
|
||||
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||||
c.JSON(422, resp.CodeMsg(40422, errMsgs))
|
||||
return
|
||||
}
|
||||
|
||||
// 当前请求信息
|
||||
ipaddr, location := reqctx.IPAddrLocation(c)
|
||||
os, browser := reqctx.UaOsBrowser(c)
|
||||
|
||||
// 校验验证码 根据错误信息,创建系统访问记录
|
||||
if err := s.accountService.ValidateCaptcha(body.Code, body.UUID); err != nil {
|
||||
msg := fmt.Sprintf("%s code: %s", err.Error(), body.Code)
|
||||
s.sysLogLoginService.Insert(
|
||||
body.Username, constants.STATUS_NO, msg,
|
||||
[4]string{ipaddr, location, os, browser},
|
||||
)
|
||||
c.JSON(400, resp.CodeMsg(40012, i18n.TKey(language, err.Error())))
|
||||
return
|
||||
}
|
||||
|
||||
// 登录用户信息
|
||||
loginUser, err := s.accountService.ByUsername(body.Username, body.Password)
|
||||
if err != nil {
|
||||
c.JSON(200, resp.ErrMsg(i18n.TKey(language, err.Error())))
|
||||
return
|
||||
}
|
||||
|
||||
// 生成令牌,创建系统访问记录
|
||||
tokenStr := token.Create(&loginUser, [4]string{ipaddr, location, os, browser})
|
||||
if tokenStr == "" {
|
||||
c.JSON(200, resp.Err(nil))
|
||||
return
|
||||
} else {
|
||||
s.accountService.UpdateLoginDateAndIP(loginUser)
|
||||
// 登录成功
|
||||
s.sysLogLoginService.Insert(
|
||||
body.Username, constants.STATUS_YES, "app.common.loginSuccess",
|
||||
[4]string{ipaddr, location, os, browser},
|
||||
)
|
||||
}
|
||||
|
||||
c.JSON(200, resp.OkData(map[string]any{
|
||||
"accessToken": tokenStr,
|
||||
"tokenType": strings.TrimRight(constants.HEADER_PREFIX, " "),
|
||||
"expiresIn": (loginUser.ExpireTime - loginUser.LoginTime) / 1000,
|
||||
"userId": loginUser.UserId,
|
||||
}))
|
||||
}
|
||||
|
||||
// Me 登录用户信息
|
||||
//
|
||||
// GET /me
|
||||
//
|
||||
// @Tags common/authorization
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Success 200 {object} object "Response Results"
|
||||
// @Security TokenAuth
|
||||
// @Summary Login User Information
|
||||
// @Description Login User Information
|
||||
// @Router /me [get]
|
||||
func (s AccountController) Me(c *gin.Context) {
|
||||
language := reqctx.AcceptLanguage(c)
|
||||
info, err := reqctx.LoginUser(c)
|
||||
if err != nil {
|
||||
c.JSON(401, resp.CodeMsg(40003, err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
// 角色权限集合,系统管理员拥有所有权限
|
||||
isSystemUser := config.IsSystemUser(info.UserId)
|
||||
roles, perms := s.accountService.RoleAndMenuPerms(info.UserId, isSystemUser)
|
||||
|
||||
info.User.NickName = i18n.TKey(language, info.User.NickName)
|
||||
info.User.Remark = i18n.TKey(language, info.User.Remark)
|
||||
info.User.Dept.DeptName = i18n.TKey(language, info.User.Dept.DeptName)
|
||||
for ri := range info.User.Roles {
|
||||
info.User.Roles[ri].RoleName = i18n.TKey(language, info.User.Roles[ri].RoleName)
|
||||
}
|
||||
c.JSON(200, resp.OkData(map[string]any{
|
||||
"user": info.User,
|
||||
"roles": roles,
|
||||
"permissions": perms,
|
||||
}))
|
||||
}
|
||||
|
||||
// Router 登录用户路由信息
|
||||
//
|
||||
// GET /router
|
||||
//
|
||||
// @Tags common/authorization
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Success 200 {object} object "Response Results"
|
||||
// @Security TokenAuth
|
||||
// @Summary Login User Routing Information
|
||||
// @Description Login User Routing Information
|
||||
// @Router /router [get]
|
||||
func (s AccountController) Router(c *gin.Context) {
|
||||
userId := reqctx.LoginUserToUserID(c)
|
||||
|
||||
// 前端路由,系统管理员拥有所有
|
||||
isSystemUser := config.IsSystemUser(userId)
|
||||
buildMenus := s.accountService.RouteMenus(userId, isSystemUser)
|
||||
|
||||
// 闭包函数处理多语言
|
||||
language := reqctx.AcceptLanguage(c)
|
||||
var converI18n func(language string, arr *[]systemModelVO.Router)
|
||||
converI18n = func(language string, arr *[]systemModelVO.Router) {
|
||||
for i := range *arr {
|
||||
(*arr)[i].Meta.Title = i18n.TKey(language, (*arr)[i].Meta.Title)
|
||||
if len((*arr)[i].Children) > 0 {
|
||||
converI18n(language, &(*arr)[i].Children)
|
||||
}
|
||||
}
|
||||
}
|
||||
converI18n(language, &buildMenus)
|
||||
|
||||
c.JSON(200, resp.OkData(buildMenus))
|
||||
}
|
||||
|
||||
// Logout 系统登出
|
||||
//
|
||||
// POST /logout
|
||||
//
|
||||
// @Tags common/authorization
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Success 200 {object} object "Response Results"
|
||||
// @Security TokenAuth
|
||||
// @Summary System Logout
|
||||
// @Description System Logout
|
||||
// @Router /logout [post]
|
||||
func (s AccountController) Logout(c *gin.Context) {
|
||||
language := reqctx.AcceptLanguage(c)
|
||||
tokenStr := reqctx.Authorization(c)
|
||||
if tokenStr != "" {
|
||||
// 存在token时记录退出信息
|
||||
userName := token.Remove(tokenStr)
|
||||
if userName != "" {
|
||||
// 当前请求信息
|
||||
ipaddr, location := reqctx.IPAddrLocation(c)
|
||||
os, browser := reqctx.UaOsBrowser(c)
|
||||
// 创建系统访问记录
|
||||
s.sysLogLoginService.Insert(
|
||||
userName, constants.STATUS_YES, "app.common.logoutSuccess",
|
||||
[4]string{ipaddr, location, os, browser},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
c.JSON(200, resp.OkMsg(i18n.TKey(language, "app.common.logoutSuccess")))
|
||||
}
|
||||
@@ -12,21 +12,16 @@ import (
|
||||
"be.ems/src/framework/i18n"
|
||||
"be.ems/src/framework/reqctx"
|
||||
"be.ems/src/framework/resp"
|
||||
commonService "be.ems/src/modules/common/service"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// 实例化控制层 CommonController 结构体
|
||||
var NewCommon = &CommonController{
|
||||
commontService: commonService.NewCommont,
|
||||
}
|
||||
var NewCommon = &CommonController{}
|
||||
|
||||
// 通用请求
|
||||
//
|
||||
// PATH /
|
||||
type CommonController struct {
|
||||
commontService *commonService.Commont // 通用请求服务
|
||||
}
|
||||
type CommonController struct{}
|
||||
|
||||
// Hash 哈希编码
|
||||
//
|
||||
@@ -37,10 +32,8 @@ func (s CommonController) Hash(c *gin.Context) {
|
||||
Str string `json:"str" binding:"required"`
|
||||
}
|
||||
if err := c.ShouldBindJSON(&body); err != nil {
|
||||
c.JSON(200, gin.H{
|
||||
"code": 400,
|
||||
"msg": "参数错误",
|
||||
})
|
||||
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||||
c.JSON(422, resp.CodeMsg(422001, errMsgs))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -100,29 +93,3 @@ func (s *CommonController) I18n(c *gin.Context) {
|
||||
"errorFields": errorFields,
|
||||
})
|
||||
}
|
||||
|
||||
// 系统的配置信息
|
||||
//
|
||||
// GET /sys-conf
|
||||
//
|
||||
// @Tags common
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Success 200 {object} object "Response Results"
|
||||
// @Summary Configuration information for the system
|
||||
// @Description Configuration information for the system
|
||||
// @Router /sys-conf [get]
|
||||
func (s CommonController) SysConfig(c *gin.Context) {
|
||||
data := s.commontService.SystemConfigInfo()
|
||||
|
||||
// 闭包函数处理多语言
|
||||
language := reqctx.AcceptLanguage(c)
|
||||
converI18n := func(language string, arr *map[string]string) {
|
||||
for k, v := range *arr {
|
||||
(*arr)[k] = i18n.TKey(language, v)
|
||||
}
|
||||
}
|
||||
converI18n(language, &data)
|
||||
|
||||
c.JSON(200, resp.OkData(data))
|
||||
}
|
||||
|
||||
@@ -4,7 +4,9 @@ import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"be.ems/src/framework/config"
|
||||
@@ -32,13 +34,13 @@ func (s *FileController) Download(c *gin.Context) {
|
||||
language := reqctx.AcceptLanguage(c)
|
||||
filePath := c.Param("filePath")
|
||||
if len(filePath) < 8 {
|
||||
c.JSON(400, resp.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
|
||||
c.JSON(422, resp.CodeMsg(422002, i18n.TKey(language, "app.common.err400")))
|
||||
return
|
||||
}
|
||||
// base64解析出地址
|
||||
decodedBytes, err := base64.StdEncoding.DecodeString(filePath)
|
||||
if err != nil {
|
||||
c.JSON(400, resp.CodeMsg(400, err.Error()))
|
||||
c.JSON(422, resp.CodeMsg(422002, err.Error()))
|
||||
return
|
||||
}
|
||||
routerPath := string(decodedBytes)
|
||||
@@ -85,14 +87,14 @@ func (s *FileController) Upload(c *gin.Context) {
|
||||
// 上传的文件
|
||||
formFile, err := c.FormFile("file")
|
||||
if err != nil {
|
||||
c.JSON(400, resp.CodeMsg(40010, "bind err: file is empty"))
|
||||
c.JSON(422, resp.CodeMsg(422002, "bind err: file is empty"))
|
||||
return
|
||||
}
|
||||
// 子路径需要在指定范围内
|
||||
subPath := c.PostForm("subPath")
|
||||
_, ok := constants.UPLOAD_SUB_PATH[subPath]
|
||||
if subPath != "" && !ok {
|
||||
c.JSON(400, resp.CodeMsg(40010, "bind err: subPath not in range"))
|
||||
c.JSON(422, resp.CodeMsg(422002, "bind err: subPath not in range"))
|
||||
return
|
||||
}
|
||||
if subPath == "" {
|
||||
@@ -132,9 +134,9 @@ func (s *FileController) ChunkCheck(c *gin.Context) {
|
||||
Identifier string `json:"identifier" binding:"required"` // 唯一标识
|
||||
FileName string `json:"fileName" binding:"required"` // 文件名
|
||||
}
|
||||
if err := c.ShouldBindJSON(&body); err != nil {
|
||||
if err := c.ShouldBindBodyWithJSON(&body); err != nil {
|
||||
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||||
c.JSON(422, resp.CodeMsg(40422, errMsgs))
|
||||
c.JSON(422, resp.CodeMsg(422001, errMsgs))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -166,14 +168,14 @@ func (s *FileController) ChunkMerge(c *gin.Context) {
|
||||
FileName string `json:"fileName" binding:"required"` // 文件名
|
||||
SubPath string `json:"subPath"` // 子路径类型
|
||||
}
|
||||
if err := c.ShouldBindJSON(&body); err != nil {
|
||||
if err := c.ShouldBindBodyWithJSON(&body); err != nil {
|
||||
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||||
c.JSON(422, resp.CodeMsg(40422, errMsgs))
|
||||
c.JSON(422, resp.CodeMsg(422001, errMsgs))
|
||||
return
|
||||
}
|
||||
// 子路径需要在指定范围内
|
||||
if _, ok := constants.UPLOAD_SUB_PATH[body.SubPath]; body.SubPath != "" && !ok {
|
||||
c.JSON(400, resp.CodeMsg(40010, "bind err: subPath not in range"))
|
||||
c.JSON(422, resp.CodeMsg(422002, "bind err: subPath not in range"))
|
||||
return
|
||||
}
|
||||
if body.SubPath == "" {
|
||||
@@ -216,13 +218,13 @@ func (s *FileController) ChunkUpload(c *gin.Context) {
|
||||
// 切片唯一标识
|
||||
identifier := c.PostForm("identifier")
|
||||
if index == "" || identifier == "" {
|
||||
c.JSON(400, resp.CodeMsg(40010, "bind err: index and identifier must be set"))
|
||||
c.JSON(422, resp.CodeMsg(422002, "bind err: index and identifier must be set"))
|
||||
return
|
||||
}
|
||||
// 上传的文件
|
||||
formFile, err := c.FormFile("file")
|
||||
if err != nil {
|
||||
c.JSON(400, resp.CodeMsg(40010, "bind err: file is empty"))
|
||||
c.JSON(422, resp.CodeMsg(422002, "bind err: file is empty"))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -235,6 +237,176 @@ func (s *FileController) ChunkUpload(c *gin.Context) {
|
||||
c.JSON(206, resp.OkData(chunkFilePath))
|
||||
}
|
||||
|
||||
// 本地文件列表
|
||||
//
|
||||
// GET /list
|
||||
//
|
||||
// @Tags common/file
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param path query string true "file path" default(/var/log)
|
||||
// @Param pageNum query number true "pageNum" default(1)
|
||||
// @Param pageSize query number true "pageSize" default(10)
|
||||
// @Param search query string false "search prefix" default(upf)
|
||||
// @Success 200 {object} object "Response Results"
|
||||
// @Security TokenAuth
|
||||
// @Summary Local file list
|
||||
// @Description Local file list
|
||||
// @Router /file/list [get]
|
||||
func (s *FileController) List(c *gin.Context) {
|
||||
var querys struct {
|
||||
Path string `form:"path" binding:"required"`
|
||||
PageNum int64 `form:"pageNum" binding:"required"`
|
||||
PageSize int64 `form:"pageSize" binding:"required"`
|
||||
Search string `form:"search"`
|
||||
}
|
||||
if err := c.ShouldBindQuery(&querys); err != nil {
|
||||
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||||
c.JSON(422, resp.CodeMsg(422001, errMsgs))
|
||||
return
|
||||
}
|
||||
|
||||
// 获取文件列表
|
||||
localFilePath := querys.Path
|
||||
if runtime.GOOS == "windows" {
|
||||
localFilePath = fmt.Sprintf("C:%s", localFilePath)
|
||||
}
|
||||
rows, err := file.FileList(localFilePath, querys.Search)
|
||||
if err != nil {
|
||||
c.JSON(200, resp.OkData(map[string]any{
|
||||
"path": querys.Path,
|
||||
"total": len(rows),
|
||||
"rows": []file.FileListRow{},
|
||||
}))
|
||||
return
|
||||
}
|
||||
|
||||
// 对数组进行切片分页
|
||||
lenNum := int64(len(rows))
|
||||
start := (querys.PageNum - 1) * querys.PageSize
|
||||
end := start + querys.PageSize
|
||||
var splitRows []file.FileListRow
|
||||
if start >= lenNum {
|
||||
splitRows = []file.FileListRow{}
|
||||
} else if end >= lenNum {
|
||||
splitRows = rows[start:]
|
||||
} else {
|
||||
splitRows = rows[start:end]
|
||||
}
|
||||
|
||||
c.JSON(200, resp.OkData(map[string]any{
|
||||
"path": querys.Path,
|
||||
"total": lenNum,
|
||||
"rows": splitRows,
|
||||
}))
|
||||
}
|
||||
|
||||
// 本地文件获取下载
|
||||
//
|
||||
// DELETE /
|
||||
//
|
||||
// @Tags common/file
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param path query string true "file path" default(/var/log)
|
||||
// @Param fileName query string true "file name" default(omc.log)
|
||||
// @Success 200 {object} object "Response Results"
|
||||
// @Security TokenAuth
|
||||
// @Summary Local files for download
|
||||
// @Description Local files for download
|
||||
// @Router /file [get]
|
||||
func (s *FileController) File(c *gin.Context) {
|
||||
var querys struct {
|
||||
Path string `form:"path" binding:"required"`
|
||||
Filename string `form:"fileName" binding:"required"`
|
||||
}
|
||||
if err := c.ShouldBindQuery(&querys); err != nil {
|
||||
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||||
c.JSON(422, resp.CodeMsg(422001, errMsgs))
|
||||
return
|
||||
}
|
||||
|
||||
// 检查路径是否在允许的目录范围内
|
||||
allowedPaths := []string{"/var/log", "/tmp", "/usr/local/omc/backup"}
|
||||
allowed := false
|
||||
for _, p := range allowedPaths {
|
||||
if strings.HasPrefix(querys.Path, p) {
|
||||
allowed = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !allowed {
|
||||
c.JSON(200, resp.ErrMsg("operation path is not within the allowed range"))
|
||||
return
|
||||
}
|
||||
|
||||
// 获取文件路径并下载
|
||||
localFilePath := filepath.Join(querys.Path, querys.Filename)
|
||||
if runtime.GOOS == "windows" {
|
||||
localFilePath = fmt.Sprintf("C:%s", localFilePath)
|
||||
}
|
||||
if _, err := os.Stat(localFilePath); os.IsNotExist(err) {
|
||||
c.JSON(200, resp.ErrMsg("file does not exist"))
|
||||
return
|
||||
}
|
||||
c.FileAttachment(localFilePath, querys.Filename)
|
||||
}
|
||||
|
||||
// 本地文件删除
|
||||
//
|
||||
// DELETE /
|
||||
//
|
||||
// @Tags common/file
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param path query string true "file path" default(/var/log)
|
||||
// @Param fileName query string true "file name" default(omc.log)
|
||||
// @Success 200 {object} object "Response Results"
|
||||
// @Security TokenAuth
|
||||
// @Summary Local file deletion
|
||||
// @Description Local file deletion
|
||||
// @Router /file [delete]
|
||||
func (s *FileController) Remove(c *gin.Context) {
|
||||
var querys struct {
|
||||
Path string `form:"path" binding:"required"`
|
||||
Filename string `form:"fileName" binding:"required"`
|
||||
}
|
||||
if err := c.ShouldBindQuery(&querys); err != nil {
|
||||
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||||
c.JSON(422, resp.CodeMsg(422001, errMsgs))
|
||||
return
|
||||
}
|
||||
|
||||
// 检查路径是否在允许的目录范围内
|
||||
allowedPaths := []string{"/tmp", "/usr/local/omc/backup"}
|
||||
allowed := false
|
||||
for _, p := range allowedPaths {
|
||||
if strings.HasPrefix(querys.Path, p) {
|
||||
allowed = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !allowed {
|
||||
c.JSON(200, resp.ErrMsg("operation path is not within the allowed range"))
|
||||
return
|
||||
}
|
||||
|
||||
// 获取文件路径并删除
|
||||
localFilePath := filepath.Join(querys.Path, querys.Filename)
|
||||
if runtime.GOOS == "windows" {
|
||||
localFilePath = fmt.Sprintf("C:%s", localFilePath)
|
||||
}
|
||||
if _, err := os.Stat(localFilePath); os.IsNotExist(err) {
|
||||
c.JSON(200, resp.ErrMsg("file does not exist"))
|
||||
return
|
||||
}
|
||||
if err := os.Remove(localFilePath); err != nil {
|
||||
c.JSON(200, resp.ErrMsg(err.Error()))
|
||||
return
|
||||
}
|
||||
c.JSON(200, resp.Ok(nil))
|
||||
}
|
||||
|
||||
// 转存指定对应文件到静态目录
|
||||
//
|
||||
// POST /transfer-static-file
|
||||
@@ -246,7 +418,7 @@ func (s *FileController) TransferStaticFile(c *gin.Context) {
|
||||
}
|
||||
if err := c.ShouldBindBodyWithJSON(&body); err != nil {
|
||||
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||||
c.JSON(422, resp.CodeMsg(40422, errMsgs))
|
||||
c.JSON(422, resp.CodeMsg(422001, errMsgs))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -257,7 +429,7 @@ func (s *FileController) TransferStaticFile(c *gin.Context) {
|
||||
static := config.Get("staticFile.default").(map[string]any)
|
||||
dir, err := filepath.Abs(static["dir"].(string))
|
||||
if err != nil {
|
||||
c.JSON(400, resp.CodeMsg(400, err.Error()))
|
||||
c.JSON(200, resp.ErrMsg(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -267,7 +439,7 @@ func (s *FileController) TransferStaticFile(c *gin.Context) {
|
||||
|
||||
err = file.CopyUploadFile(body.UploadPath, newFile)
|
||||
if err != nil {
|
||||
c.JSON(400, resp.CodeMsg(400, err.Error()))
|
||||
c.JSON(200, resp.ErrMsg(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
libGlobal "be.ems/lib/global"
|
||||
"be.ems/src/framework/config"
|
||||
"be.ems/src/framework/resp"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
@@ -29,9 +27,9 @@ type IndexController struct{}
|
||||
// @Description Root Route
|
||||
// @Router / [get]
|
||||
func (s *IndexController) Handler(c *gin.Context) {
|
||||
name := "OMC"
|
||||
version := libGlobal.Version
|
||||
// str := "欢迎使用%s核心网管理平台,当前版本:%s,请通过前台地址访问。"
|
||||
str := "%s Core Network Management, current version: %s"
|
||||
c.JSON(200, resp.OkMsg(fmt.Sprintf(str, name, version)))
|
||||
c.JSON(200, resp.OkData(map[string]any{
|
||||
"name": "OMC",
|
||||
"version": config.Version,
|
||||
}))
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
package exportTable
|
||||
package backup_export_table
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -12,25 +12,27 @@ import (
|
||||
"be.ems/src/framework/database/db"
|
||||
"be.ems/src/framework/i18n"
|
||||
"be.ems/src/framework/logger"
|
||||
"be.ems/src/framework/ssh"
|
||||
"be.ems/src/framework/utils/date"
|
||||
"be.ems/src/framework/utils/file"
|
||||
"be.ems/src/framework/utils/parse"
|
||||
neDataModel "be.ems/src/modules/network_data/model"
|
||||
neDataService "be.ems/src/modules/network_data/service"
|
||||
systemModel "be.ems/src/modules/system/model"
|
||||
systemService "be.ems/src/modules/system/service"
|
||||
)
|
||||
|
||||
var NewProcessor = &BarProcessor{
|
||||
count: 0,
|
||||
var NewProcessor = &BackupExportTableProcessor{
|
||||
backupService: neDataService.NewBackup,
|
||||
count: 0,
|
||||
}
|
||||
|
||||
// bar 队列任务处理
|
||||
type BarProcessor struct {
|
||||
count int // 执行次数
|
||||
// BackupExportTable 备份导出数据表
|
||||
type BackupExportTableProcessor struct {
|
||||
backupService *neDataService.Backup // 备份相关服务
|
||||
count int // 执行次数
|
||||
}
|
||||
|
||||
func (s *BarProcessor) Execute(data any) (any, error) {
|
||||
func (s *BackupExportTableProcessor) Execute(data any) (any, error) {
|
||||
s.count++ // 执行次数加一
|
||||
options := data.(cron.JobData)
|
||||
sysJob := options.SysJob
|
||||
@@ -41,10 +43,10 @@ func (s *BarProcessor) Execute(data any) (any, error) {
|
||||
}
|
||||
|
||||
var params struct {
|
||||
Hour int `json:"hour"` // hour
|
||||
TableName string `json:"tableName"`
|
||||
Columns []string `json:"columns"`
|
||||
FilePath string `json:"filePath"` // file path
|
||||
Hour int `json:"hour"` // 数据时间从任务执行时间前的小时数
|
||||
TableName string `json:"tableName"` // 数据表名
|
||||
Columns []string `json:"columns"` // 支持字段
|
||||
BackupPath string `json:"backupPath"` // 备份输出路径 /usr/local/omc/backup/{backupPath}
|
||||
}
|
||||
err := json.Unmarshal([]byte(sysJob.TargetParams), ¶ms)
|
||||
if err != nil {
|
||||
@@ -53,7 +55,11 @@ func (s *BarProcessor) Execute(data any) (any, error) {
|
||||
|
||||
var affected int64
|
||||
var errMsg error
|
||||
filePath := fmt.Sprintf("%s/%s_export_%s.csv", params.FilePath, strings.ToLower(params.TableName), time.Now().Format("20060102150405"))
|
||||
fileName := fmt.Sprintf("%s_export_%s.csv", strings.ToLower(params.TableName), time.Now().Format("20060102150405"))
|
||||
filePath := filepath.Join("/usr/local/omc/backup", params.BackupPath, fileName)
|
||||
if runtime.GOOS == "windows" {
|
||||
filePath = fmt.Sprintf("C:%s", filePath)
|
||||
}
|
||||
switch params.TableName {
|
||||
case "sys_log_operate":
|
||||
affected, errMsg = s.exportSysLogOperate(params.Hour, params.Columns, filePath)
|
||||
@@ -70,18 +76,20 @@ func (s *BarProcessor) Execute(data any) (any, error) {
|
||||
return nil, errMsg
|
||||
}
|
||||
|
||||
// put ftp
|
||||
// 上传到FTP服务器
|
||||
if affected > 0 {
|
||||
result["affected"] = affected
|
||||
s.putFTP(filePath)
|
||||
if err := s.backupService.FTPPushFile(filePath, params.BackupPath); err != nil {
|
||||
result["ftpErr"] = err.Error()
|
||||
}
|
||||
}
|
||||
result["affected"] = affected
|
||||
|
||||
// 返回结果,用于记录执行结果
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// exportSysLogOperate 导出csv
|
||||
func (s BarProcessor) exportSysLogOperate(hour int, columns []string, filePath string) (int64, error) {
|
||||
func (s BackupExportTableProcessor) exportSysLogOperate(hour int, columns []string, filePath string) (int64, error) {
|
||||
// 前 hour 小时
|
||||
now := time.Now()
|
||||
end := time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), 0, 0, 0, now.Location())
|
||||
@@ -182,7 +190,7 @@ func (s BarProcessor) exportSysLogOperate(hour int, columns []string, filePath s
|
||||
}
|
||||
|
||||
// exportSMF 导出csv
|
||||
func (s BarProcessor) exportSMF(hour int, columns []string, filePath string) (int64, error) {
|
||||
func (s BackupExportTableProcessor) exportSMF(hour int, columns []string, filePath string) (int64, error) {
|
||||
// 前 hour 小时
|
||||
now := time.Now()
|
||||
end := time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), 0, 0, 0, now.Location())
|
||||
@@ -413,7 +421,7 @@ func (s BarProcessor) exportSMF(hour int, columns []string, filePath string) (in
|
||||
}
|
||||
|
||||
// exportIMS 导出csv
|
||||
func (s BarProcessor) exportIMS(hour int, columns []string, filePath string) (int64, error) {
|
||||
func (s BackupExportTableProcessor) exportIMS(hour int, columns []string, filePath string) (int64, error) {
|
||||
// 前 hour 小时
|
||||
now := time.Now()
|
||||
end := time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), 0, 0, 0, now.Location())
|
||||
@@ -521,7 +529,6 @@ func (s BarProcessor) exportIMS(hour int, columns []string, filePath string) (in
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
arr[i] = callResult
|
||||
}
|
||||
@@ -558,7 +565,7 @@ func (s BarProcessor) exportIMS(hour int, columns []string, filePath string) (in
|
||||
}
|
||||
|
||||
// exportSMSC 导出csv
|
||||
func (s BarProcessor) exportSMSC(hour int, columns []string, filePath string) (int64, error) {
|
||||
func (s BackupExportTableProcessor) exportSMSC(hour int, columns []string, filePath string) (int64, error) {
|
||||
// 前 hour 小时
|
||||
now := time.Now()
|
||||
end := time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), 0, 0, 0, now.Location())
|
||||
@@ -683,7 +690,7 @@ func (s BarProcessor) exportSMSC(hour int, columns []string, filePath string) (i
|
||||
}
|
||||
|
||||
// exportSGWC 导出csv
|
||||
func (s BarProcessor) exportSGWC(hour int, columns []string, filePath string) (int64, error) {
|
||||
func (s BackupExportTableProcessor) exportSGWC(hour int, columns []string, filePath string) (int64, error) {
|
||||
// 前 hour 小时
|
||||
now := time.Now()
|
||||
end := time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), 0, 0, 0, now.Location())
|
||||
@@ -918,54 +925,3 @@ func (s BarProcessor) exportSGWC(hour int, columns []string, filePath string) (i
|
||||
|
||||
return tx.RowsAffected, err
|
||||
}
|
||||
|
||||
// putFTP 提交到服务器ssh
|
||||
func (s BarProcessor) putFTP(localFilePath string) {
|
||||
// 获取配置
|
||||
var cfgData struct {
|
||||
Password string `json:"password" `
|
||||
Username string `json:"username" binding:"required"`
|
||||
ToIp string `json:"toIp" binding:"required"`
|
||||
ToPort int64 `json:"toPort" binding:"required"`
|
||||
Enable bool `json:"enable"`
|
||||
Dir string `json:"dir" binding:"required"`
|
||||
}
|
||||
cfg := systemService.NewSysConfig.FindByKeyDecryptValue("neData.exportTableFTP")
|
||||
if cfg.ConfigId > 0 {
|
||||
if err := json.Unmarshal([]byte(cfg.ConfigValue), &cfgData); err != nil {
|
||||
logger.Errorf("putFTP unmarshal error: %v", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
if !cfgData.Enable {
|
||||
return
|
||||
}
|
||||
|
||||
connSSH := ssh.ConnSSH{
|
||||
User: cfgData.Username,
|
||||
Password: cfgData.Password,
|
||||
Addr: cfgData.ToIp,
|
||||
Port: cfgData.ToPort,
|
||||
AuthMode: "0",
|
||||
}
|
||||
sshClient, err := connSSH.NewClient()
|
||||
if err != nil {
|
||||
logger.Errorf("putFTP ssh error: %v", err)
|
||||
return
|
||||
}
|
||||
defer sshClient.Close()
|
||||
// 网元主机的SSH客户端进行文件传输
|
||||
sftpClient, err := sshClient.NewClientSFTP()
|
||||
if err != nil {
|
||||
logger.Errorf("putFTP sftp error: %v", err)
|
||||
return
|
||||
}
|
||||
defer sftpClient.Close()
|
||||
// 远程文件
|
||||
remotePath := filepath.Join(cfgData.Dir, path.Base(localFilePath), filepath.Base(localFilePath))
|
||||
// 复制到远程
|
||||
if err = sftpClient.CopyFileLocalToRemote(localFilePath, remotePath); err != nil {
|
||||
logger.Errorf("putFTP uploading error: %v", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,273 @@
|
||||
package backup_export_udm
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"time"
|
||||
|
||||
"be.ems/src/framework/cron"
|
||||
"be.ems/src/framework/logger"
|
||||
"be.ems/src/framework/utils/file"
|
||||
neDataModel "be.ems/src/modules/network_data/model"
|
||||
neDataService "be.ems/src/modules/network_data/service"
|
||||
neModel "be.ems/src/modules/network_element/model"
|
||||
neService "be.ems/src/modules/network_element/service"
|
||||
)
|
||||
|
||||
var NewProcessor = &BackupExportUDMProcessor{
|
||||
count: 0,
|
||||
neInfoService: neService.NewNeInfo,
|
||||
backupService: neDataService.NewBackup,
|
||||
udmAuthService: neDataService.NewUDMAuthUser,
|
||||
udmSubService: neDataService.NewUDMSubUser,
|
||||
udmVOIPService: neDataService.NewUDMVOIPUser,
|
||||
udmVolteIMSService: neDataService.NewUDMVolteIMSUser,
|
||||
}
|
||||
|
||||
// BackupExportUDM 队列任务处理
|
||||
type BackupExportUDMProcessor struct {
|
||||
count int // 执行次数
|
||||
neInfoService *neService.NeInfo // 网元信息服务
|
||||
backupService *neDataService.Backup // 备份相关服务
|
||||
udmAuthService *neDataService.UDMAuthUser // UDM鉴权信息服务
|
||||
udmSubService *neDataService.UDMSubUser // UDM签约信息服务
|
||||
udmVOIPService *neDataService.UDMVOIPUser // UDMVOIP信息服务
|
||||
udmVolteIMSService *neDataService.UDMVolteIMSUser // UDMVolteIMS信息服务
|
||||
}
|
||||
|
||||
func (s *BackupExportUDMProcessor) Execute(data any) (any, error) {
|
||||
s.count++ // 执行次数加一
|
||||
options := data.(cron.JobData)
|
||||
sysJob := options.SysJob
|
||||
logger.Infof("重复:%v 任务ID:%d 执行次数:%d", options.Repeat, sysJob.JobId, s.count)
|
||||
// 返回结果,用于记录执行结果
|
||||
result := map[string]any{
|
||||
"count": s.count,
|
||||
}
|
||||
|
||||
var params struct {
|
||||
DataType []string `json:"dataType"` // 类型支持 auth/sub/voip/volte
|
||||
FileType string `json:"fileType"` // 文件类型 csv/txt
|
||||
}
|
||||
if err := json.Unmarshal([]byte(sysJob.TargetParams), ¶ms); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !(params.FileType == "csv" || params.FileType == "txt") {
|
||||
return nil, fmt.Errorf("file type error, only support csv,txt")
|
||||
}
|
||||
|
||||
neList := s.neInfoService.Find(neModel.NeInfo{NeType: "UDM"}, false, false)
|
||||
for _, neInfo := range neList {
|
||||
for _, v := range params.DataType {
|
||||
switch v {
|
||||
case "auth":
|
||||
result[fmt.Sprintf("%s-%s", neInfo.NeId, v)] = s.exportAuth(neInfo.NeId, params.FileType)
|
||||
case "sub":
|
||||
result[fmt.Sprintf("%s-%s", neInfo.NeId, v)] = s.exportSub(neInfo.NeId, params.FileType)
|
||||
case "voip":
|
||||
result[fmt.Sprintf("%s-%s", neInfo.NeId, v)] = s.exportVOIP(neInfo.NeId, params.FileType)
|
||||
case "volte":
|
||||
result[fmt.Sprintf("%s-%s", neInfo.NeId, v)] = s.exportVolte(neInfo.NeId, params.FileType)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 返回结果,用于记录执行结果
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// exportAuth 导出鉴权用户数据
|
||||
func (s BackupExportUDMProcessor) exportAuth(neId, fileType string) string {
|
||||
rows := s.udmAuthService.Find(neDataModel.UDMAuthUser{NeId: neId})
|
||||
if len(rows) <= 0 {
|
||||
return "no data"
|
||||
}
|
||||
|
||||
// 文件名
|
||||
fileName := fmt.Sprintf("auth_%s_export_%s.%s", neId, time.Now().Format("20060102150405"), fileType)
|
||||
filePath := filepath.Join("/usr/local/omc/backup/udm_data/auth", fileName)
|
||||
if runtime.GOOS == "windows" {
|
||||
filePath = fmt.Sprintf("C:%s", filePath)
|
||||
}
|
||||
|
||||
if fileType == "csv" {
|
||||
// 转换数据
|
||||
data := [][]string{}
|
||||
data = append(data, []string{"imsi", "ki", "algo", "amf", "opc"})
|
||||
for _, v := range rows {
|
||||
opc := v.Opc
|
||||
if opc == "-" {
|
||||
opc = ""
|
||||
}
|
||||
data = append(data, []string{v.IMSI, v.Ki, v.AlgoIndex, v.Amf, opc})
|
||||
}
|
||||
// 输出到文件
|
||||
if err := file.WriterFileCSV(data, filePath); err != nil {
|
||||
return err.Error()
|
||||
}
|
||||
}
|
||||
|
||||
if fileType == "txt" {
|
||||
// 转换数据
|
||||
data := [][]string{}
|
||||
for _, v := range rows {
|
||||
opc := v.Opc
|
||||
if opc == "-" {
|
||||
opc = ""
|
||||
}
|
||||
data = append(data, []string{v.IMSI, v.Ki, v.AlgoIndex, v.Amf, opc})
|
||||
}
|
||||
// 输出到文件
|
||||
if err := file.WriterFileTXT(data, ",", filePath); err != nil {
|
||||
return err.Error()
|
||||
}
|
||||
}
|
||||
|
||||
// 上传到FTP服务器
|
||||
if err := s.backupService.FTPPushFile(filePath, "udm_data"); err != nil {
|
||||
return "ok, ftp err:" + err.Error()
|
||||
}
|
||||
return "ok"
|
||||
}
|
||||
|
||||
// exportSub 导出签约用户数据
|
||||
func (s BackupExportUDMProcessor) exportSub(neId, fileType string) string {
|
||||
rows := s.udmSubService.Find(neDataModel.UDMSubUser{NeId: neId})
|
||||
if len(rows) <= 0 {
|
||||
return "no data"
|
||||
}
|
||||
|
||||
// 文件名
|
||||
fileName := fmt.Sprintf("sub_%s_export_%s.%s", neId, time.Now().Format("20060102150405"), fileType)
|
||||
filePath := filepath.Join("/usr/local/omc/backup/udm_data/sub", fileName)
|
||||
if runtime.GOOS == "windows" {
|
||||
filePath = fmt.Sprintf("C:%s", filePath)
|
||||
}
|
||||
|
||||
if fileType == "csv" {
|
||||
// 转换数据
|
||||
data := [][]string{}
|
||||
data = append(data, []string{"IMSI", "MSISDN", "UeAmbrTpl", "NssaiTpl", "AreaForbiddenTpl", "ServiceAreaRestrictionTpl", "RatRestrictions", "CnTypeRestrictions", "SmfSel", "SmData", "EPSDat"})
|
||||
for _, v := range rows {
|
||||
epsDat := fmt.Sprintf("%s,%s,%s,%s,%s,%s,%s,%s", v.EpsFlag, v.EpsOdb, v.HplmnOdb, v.Ard, v.Epstpl, v.ContextId, v.ApnContext, v.StaticIp)
|
||||
data = append(data, []string{v.IMSI, v.MSISDN, v.UeAmbrTpl, v.NssaiTpl, v.AreaForbiddenTpl, v.ServiceAreaRestrictionTpl, v.RatRestrictions, v.CnTypeRestrictions, v.SmfSel, v.SmData, epsDat})
|
||||
}
|
||||
// 输出到文件
|
||||
if err := file.WriterFileCSV(data, filePath); err != nil {
|
||||
return err.Error()
|
||||
}
|
||||
}
|
||||
|
||||
if fileType == "txt" {
|
||||
// 转换数据
|
||||
data := [][]string{}
|
||||
for _, v := range rows {
|
||||
epsDat := fmt.Sprintf("%s,%s,%s,%s,%s,%s,%s,%s", v.EpsFlag, v.EpsOdb, v.HplmnOdb, v.Ard, v.Epstpl, v.ContextId, v.ApnContext, v.StaticIp)
|
||||
data = append(data, []string{v.IMSI, v.MSISDN, v.UeAmbrTpl, v.NssaiTpl, v.AreaForbiddenTpl, v.ServiceAreaRestrictionTpl, v.RatRestrictions, v.CnTypeRestrictions, v.SmfSel, v.SmData, epsDat})
|
||||
}
|
||||
// 输出到文件
|
||||
if err := file.WriterFileTXT(data, ",", filePath); err != nil {
|
||||
return err.Error()
|
||||
}
|
||||
}
|
||||
|
||||
// 上传到FTP服务器
|
||||
if err := s.backupService.FTPPushFile(filePath, "udm_data"); err != nil {
|
||||
return "ok, ftp err:" + err.Error()
|
||||
}
|
||||
return "ok"
|
||||
}
|
||||
|
||||
// exportVOIP 导出VOIP用户数据
|
||||
func (s BackupExportUDMProcessor) exportVOIP(neId, fileType string) string {
|
||||
rows := s.udmVOIPService.Find(neDataModel.UDMVOIPUser{NeId: neId})
|
||||
if len(rows) <= 0 {
|
||||
return "no data"
|
||||
}
|
||||
|
||||
// 文件名
|
||||
fileName := fmt.Sprintf("voip_%s_export_%s.%s", neId, time.Now().Format("20060102150405"), fileType)
|
||||
filePath := filepath.Join("/usr/local/omc/backup/udm_data/voip", fileName)
|
||||
if runtime.GOOS == "windows" {
|
||||
filePath = fmt.Sprintf("C:%s", filePath)
|
||||
}
|
||||
|
||||
if fileType == "csv" {
|
||||
// 转换数据
|
||||
data := [][]string{}
|
||||
data = append(data, []string{"username", "password"})
|
||||
for _, v := range rows {
|
||||
data = append(data, []string{v.UserName, v.Password})
|
||||
}
|
||||
// 输出到文件
|
||||
if err := file.WriterFileCSV(data, filePath); err != nil {
|
||||
return err.Error()
|
||||
}
|
||||
}
|
||||
|
||||
if fileType == "txt" {
|
||||
// 转换数据
|
||||
data := [][]string{}
|
||||
for _, v := range rows {
|
||||
data = append(data, []string{v.UserName, v.Password})
|
||||
}
|
||||
// 输出到文件
|
||||
if err := file.WriterFileTXT(data, ",", filePath); err != nil {
|
||||
return err.Error()
|
||||
}
|
||||
}
|
||||
|
||||
// 上传到FTP服务器
|
||||
if err := s.backupService.FTPPushFile(filePath, "udm_data"); err != nil {
|
||||
return "ok, ftp err:" + err.Error()
|
||||
}
|
||||
return "ok"
|
||||
}
|
||||
|
||||
// exportVolte 导出Volte用户数据
|
||||
func (s BackupExportUDMProcessor) exportVolte(neId, fileType string) string {
|
||||
rows := s.udmVolteIMSService.Find(neDataModel.UDMVolteIMSUser{NeId: neId})
|
||||
if len(rows) <= 0 {
|
||||
return "no data"
|
||||
}
|
||||
|
||||
// 文件名
|
||||
fileName := fmt.Sprintf("volte_%s_export_%s.%s", neId, time.Now().Format("20060102150405"), fileType)
|
||||
filePath := filepath.Join("/usr/local/omc/backup/udm_data/volte", fileName)
|
||||
if runtime.GOOS == "windows" {
|
||||
filePath = fmt.Sprintf("C:%s", filePath)
|
||||
}
|
||||
|
||||
if fileType == "csv" {
|
||||
// 转换数据
|
||||
data := [][]string{}
|
||||
data = append(data, []string{"IMSI", "MSISDN", "TAG", "VNI"})
|
||||
for _, v := range rows {
|
||||
data = append(data, []string{v.IMSI, v.MSISDN, v.Tag, v.VNI})
|
||||
}
|
||||
// 输出到文件
|
||||
if err := file.WriterFileCSV(data, filePath); err != nil {
|
||||
return err.Error()
|
||||
}
|
||||
}
|
||||
|
||||
if fileType == "txt" {
|
||||
// 转换数据
|
||||
data := [][]string{}
|
||||
for _, v := range rows {
|
||||
data = append(data, []string{v.IMSI, v.MSISDN, v.Tag, v.VNI})
|
||||
}
|
||||
// 输出到文件
|
||||
if err := file.WriterFileTXT(data, ",", filePath); err != nil {
|
||||
return err.Error()
|
||||
}
|
||||
}
|
||||
|
||||
// 上传到FTP服务器
|
||||
if err := s.backupService.FTPPushFile(filePath, "udm_data"); err != nil {
|
||||
return "ok, ftp err:" + err.Error()
|
||||
}
|
||||
return "ok"
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
package backup_remove_file
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"be.ems/src/framework/cron"
|
||||
"be.ems/src/framework/logger"
|
||||
)
|
||||
|
||||
type FileInfo struct {
|
||||
Path string
|
||||
Info os.FileInfo
|
||||
}
|
||||
|
||||
var NewProcessor = &BackupRemoveFileProcessor{
|
||||
count: 0,
|
||||
}
|
||||
|
||||
// BackupRemoveFileProcessor 删除备份文件
|
||||
type BackupRemoveFileProcessor struct {
|
||||
count int // 执行次数
|
||||
}
|
||||
|
||||
func (s *BackupRemoveFileProcessor) Execute(data any) (any, error) {
|
||||
s.count++ // 执行次数加一
|
||||
options := data.(cron.JobData)
|
||||
sysJob := options.SysJob
|
||||
logger.Infof("重复:%v 任务ID:%d 执行次数:%d", options.Repeat, sysJob.JobId, s.count)
|
||||
// 返回结果,用于记录执行结果
|
||||
result := map[string]any{
|
||||
"count": s.count,
|
||||
}
|
||||
|
||||
// 读取参数值
|
||||
var params []struct {
|
||||
BackupPath string `json:"backupPath"` // 备份路径 /usr/local/omc/backup/{backupPath}
|
||||
StoreDays int `json:"storeDays"` // 保留天数
|
||||
StoreNum int `json:"storeNum"` // 保留数量,默认保留7
|
||||
}
|
||||
err := json.Unmarshal([]byte(sysJob.TargetParams), ¶ms)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("json params err: %v", err)
|
||||
}
|
||||
|
||||
for _, item := range params {
|
||||
result[item.BackupPath] = ""
|
||||
if item.StoreDays < 0 {
|
||||
result[item.BackupPath] = "params storeDays less than 0"
|
||||
continue
|
||||
}
|
||||
if item.StoreNum <= 0 {
|
||||
item.StoreNum = 7
|
||||
}
|
||||
|
||||
// 构建完整备份路径
|
||||
filePath := filepath.Join("/usr/local/omc/backup", item.BackupPath)
|
||||
if runtime.GOOS == "windows" {
|
||||
filePath = fmt.Sprintf("C:%s", filePath)
|
||||
}
|
||||
// 获取目录下所有备份文件
|
||||
files, err := s.files(filePath)
|
||||
if err != nil {
|
||||
result[item.BackupPath] = "read files err"
|
||||
continue
|
||||
}
|
||||
// 按修改时间排序(从旧到新)
|
||||
sort.Slice(files, func(i, j int) bool {
|
||||
return files[i].Info.ModTime().Before(files[j].Info.ModTime())
|
||||
})
|
||||
|
||||
// 如果文件数量少于保留数量,则不删除
|
||||
if len(files) <= item.StoreNum {
|
||||
result[item.BackupPath] = fmt.Sprintf("less StoreNum: %d, file number %d", item.StoreNum, len(files))
|
||||
continue
|
||||
}
|
||||
// 计算截止日期
|
||||
cutoff := time.Now().AddDate(0, 0, -item.StoreDays)
|
||||
// 删除超过保留天数的文件
|
||||
deletedErr := []string{}
|
||||
for _, file := range files {
|
||||
if file.Info.ModTime().Before(cutoff) {
|
||||
if err := os.Remove(file.Path); err != nil {
|
||||
deletedErr = append(deletedErr, file.Info.Name()) // 记录删除失败的文件名称
|
||||
}
|
||||
}
|
||||
}
|
||||
result[item.BackupPath] = strings.Join(deletedErr, ", ")
|
||||
}
|
||||
|
||||
// 返回结果,用于记录执行结果
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (s *BackupRemoveFileProcessor) files(dir string) ([]FileInfo, error) {
|
||||
var files []FileInfo
|
||||
err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !info.IsDir() {
|
||||
files = append(files, FileInfo{Path: path, Info: info})
|
||||
}
|
||||
return nil
|
||||
})
|
||||
return files, err
|
||||
}
|
||||
@@ -39,7 +39,8 @@ func (s *DeleteNeConfigBackupProcessor) Execute(data any) (any, error) {
|
||||
|
||||
// 读取参数值
|
||||
var params struct {
|
||||
StoreDays int `json:"storeDays"` // store days
|
||||
StoreDays int `json:"storeDays"` // 保留天数
|
||||
StoreNum int `json:"storeNum"` // 保留数量,默认保留7
|
||||
}
|
||||
err := json.Unmarshal([]byte(sysJob.TargetParams), ¶ms)
|
||||
if err != nil {
|
||||
@@ -48,6 +49,9 @@ func (s *DeleteNeConfigBackupProcessor) Execute(data any) (any, error) {
|
||||
if params.StoreDays < 0 {
|
||||
return nil, fmt.Errorf("params storeDays less than 0 ")
|
||||
}
|
||||
if params.StoreNum <= 0 {
|
||||
params.StoreNum = 7
|
||||
}
|
||||
|
||||
neList := s.neInfoService.Find(neModel.NeInfo{}, false, false)
|
||||
for _, neInfo := range neList {
|
||||
@@ -55,6 +59,17 @@ func (s *DeleteNeConfigBackupProcessor) Execute(data any) (any, error) {
|
||||
tx := db.DB("").Model(&neModel.NeConfigBackup{})
|
||||
tx = tx.Where("ne_type = ? and ne_id = ?", neInfo.NeType, neInfo.NeId)
|
||||
|
||||
// 查询数量为0直接返回
|
||||
var total int64 = 0
|
||||
if err := tx.Count(&total).Error; err != nil {
|
||||
result[neTypeAndId] = err.Error()
|
||||
continue
|
||||
}
|
||||
if total <= int64(params.StoreNum) {
|
||||
result[neTypeAndId] = "less than storeNum"
|
||||
continue
|
||||
}
|
||||
|
||||
// 查询最后记录数据
|
||||
var lastCreateTime int64 = 0
|
||||
lastTx := tx.Select("create_time").Order("create_time DESC").Limit(1)
|
||||
@@ -62,7 +77,6 @@ func (s *DeleteNeConfigBackupProcessor) Execute(data any) (any, error) {
|
||||
result[neTypeAndId] = err.Error()
|
||||
continue
|
||||
}
|
||||
|
||||
if lastCreateTime <= 1e12 {
|
||||
result[neTypeAndId] = "no data"
|
||||
continue
|
||||
@@ -90,7 +104,7 @@ func (s *DeleteNeConfigBackupProcessor) Execute(data any) (any, error) {
|
||||
// deleteFile 删除本地文件
|
||||
func (s DeleteNeConfigBackupProcessor) deleteFile(neType, neId string, oldFileDate time.Time) {
|
||||
neTypeLower := strings.ToLower(neType)
|
||||
localPath := fmt.Sprintf("/usr/local/etc/omc/ne_config/%s/%s/backup ", neTypeLower, neId)
|
||||
localPath := fmt.Sprintf("/usr/local/omc/backup/ne_config/%s/%s ", neTypeLower, neId)
|
||||
files, err := os.ReadDir(localPath)
|
||||
if err != nil {
|
||||
logger.Errorf("logger Remove ne_config File ReadDir err: %v", err.Error())
|
||||
|
||||
@@ -1,160 +0,0 @@
|
||||
package getStateFromNE
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"be.ems/lib/config"
|
||||
"be.ems/lib/dborm"
|
||||
"be.ems/lib/log"
|
||||
"be.ems/src/framework/cron"
|
||||
"github.com/go-resty/resty/v2"
|
||||
)
|
||||
|
||||
var NewProcessor = &BarProcessor{
|
||||
progress: 0,
|
||||
count: 0,
|
||||
}
|
||||
|
||||
// bar 队列任务处理
|
||||
type BarProcessor struct {
|
||||
// 任务进度
|
||||
progress int
|
||||
// 执行次数
|
||||
count int
|
||||
}
|
||||
|
||||
type BarParams struct {
|
||||
Duration int `json:"duration"`
|
||||
}
|
||||
|
||||
type CpuUsage struct {
|
||||
NfCpuUsage uint16 `json:"nfCpuUsage"`
|
||||
SysCpuUsage uint16 `json:"sysCpuUsage"`
|
||||
}
|
||||
|
||||
type MemUsage struct {
|
||||
TotalMem uint32 `json:"totalMem"`
|
||||
NfUsedMem uint32 `json:"nfUsedMem"`
|
||||
SysMemUsage uint16 `json:"sysMemUsage"`
|
||||
}
|
||||
|
||||
type PartitionInfo struct {
|
||||
Total uint32 `json:"total"` // MB
|
||||
Used uint32 `json:"used"` // MB
|
||||
}
|
||||
|
||||
type DiskSpace struct {
|
||||
PartitionNum uint8 `json:"partitionNum"`
|
||||
|
||||
PartitionInfo []PartitionInfo `json:"partitionInfo"`
|
||||
}
|
||||
|
||||
type SystemState struct {
|
||||
Version string `json:"version"`
|
||||
Capability uint32 `json:"capability"`
|
||||
SerialNum string `json:"serialNum"`
|
||||
ExpiryDate string `json:"expiryDate"`
|
||||
//Timestamp string `json:"timestamp"`
|
||||
|
||||
CpuUsage CpuUsage `json:"cpuUsage"`
|
||||
MemUsage MemUsage `json:"memUsage"`
|
||||
|
||||
DiskSpace DiskSpace `json:"diskSpace"`
|
||||
}
|
||||
|
||||
var client = resty.New()
|
||||
|
||||
func init() {
|
||||
client.
|
||||
SetTimeout(time.Duration(400 * time.Millisecond))
|
||||
}
|
||||
|
||||
func (s *BarProcessor) Execute(data any) (any, error) {
|
||||
var err error
|
||||
|
||||
s.count++
|
||||
options := data.(cron.JobData)
|
||||
sysJob := options.SysJob
|
||||
var params BarParams
|
||||
|
||||
_ = json.Unmarshal([]byte(sysJob.TargetParams), ¶ms)
|
||||
// if err == nil {
|
||||
// duration = params.Duration
|
||||
// }
|
||||
|
||||
var nes []dborm.NeInfo
|
||||
_, err = dborm.XormGetAllNeInfo(&nes)
|
||||
if err != nil {
|
||||
log.Error("Failed to get all ne info:", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
failNum := 0
|
||||
succNum := 0
|
||||
for _, ne := range nes {
|
||||
requestURI := fmt.Sprintf("/api/rest/systemManagement/v1/elementType/%s/objectType/systemState", strings.ToLower(ne.NeType))
|
||||
requestURL := fmt.Sprintf("http://%s:%s%s", ne.Ip, ne.Port, requestURI)
|
||||
log.Debug("requestURL: Get", requestURL)
|
||||
response, err := client.R().
|
||||
EnableTrace().
|
||||
SetHeaders(map[string]string{"User-Agent": config.GetDefaultUserAgent()}).
|
||||
SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}).
|
||||
Get(requestURL)
|
||||
if err != nil {
|
||||
log.Error("Failed to Get:", err)
|
||||
failNum++
|
||||
continue
|
||||
}
|
||||
|
||||
log.Debug("StatusCode: ", response.StatusCode())
|
||||
switch response.StatusCode() {
|
||||
case http.StatusOK, http.StatusCreated, http.StatusNoContent, http.StatusAccepted:
|
||||
log.Trace("response body:", string(response.Body()))
|
||||
state := new(SystemState)
|
||||
_ = json.Unmarshal(response.Body(), &state)
|
||||
// var dateStr *string = nil
|
||||
// if state.ExpiryDate != "" && state.ExpiryDate != "-" {
|
||||
// dateStr = &state.ExpiryDate
|
||||
// }
|
||||
neState := new(dborm.NeState)
|
||||
neState.NeType = ne.NeType
|
||||
neState.NeId = ne.NeId
|
||||
neState.Version = state.Version
|
||||
neState.Capability = state.Capability
|
||||
neState.SerialNum = state.SerialNum
|
||||
// if dateStr != nil {
|
||||
// neState.ExpiryDate = *dateStr
|
||||
// }
|
||||
neState.ExpiryDate = state.ExpiryDate
|
||||
cu, _ := json.Marshal(state.CpuUsage)
|
||||
neState.CpuUsage = string(cu)
|
||||
mu, _ := json.Marshal(state.MemUsage)
|
||||
neState.MemUsage = string(mu)
|
||||
ds, _ := json.Marshal(state.DiskSpace)
|
||||
neState.DiskSpace = string(ds)
|
||||
log.Trace("neState:", neState)
|
||||
_, err := dborm.XormInsertNeState(neState)
|
||||
if err != nil {
|
||||
log.Error("Failed to insert ne_state:", err)
|
||||
failNum++
|
||||
continue
|
||||
}
|
||||
succNum++
|
||||
default:
|
||||
log.Trace("response body:", string(response.Body()))
|
||||
body := new(map[string]interface{})
|
||||
_ = json.Unmarshal(response.Body(), &body)
|
||||
failNum++
|
||||
}
|
||||
}
|
||||
|
||||
// 返回结果,用于记录执行结果
|
||||
return map[string]any{
|
||||
"succNum": succNum,
|
||||
"failNum": failNum,
|
||||
}, nil
|
||||
}
|
||||
@@ -66,6 +66,9 @@ func (s *NeAlarmStateCheckProcessor) Execute(data any) (any, error) {
|
||||
|
||||
neList := s.neInfoService.Find(neModel.NeInfo{}, true, false)
|
||||
for _, neInfo := range neList {
|
||||
if neInfo.CreateTime == 0 {
|
||||
continue
|
||||
}
|
||||
neTypeAndId := fmt.Sprintf("%s_%s", neInfo.NeType, neInfo.NeId)
|
||||
// 网元在线状态
|
||||
isOnline := parse.Boolean(neInfo.ServerState["online"])
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
|
||||
"be.ems/src/framework/cron"
|
||||
"be.ems/src/framework/logger"
|
||||
neDataService "be.ems/src/modules/network_data/service"
|
||||
neModel "be.ems/src/modules/network_element/model"
|
||||
neService "be.ems/src/modules/network_element/service"
|
||||
)
|
||||
@@ -13,6 +14,7 @@ import (
|
||||
var NewProcessor = &NeConfigBackupProcessor{
|
||||
neConfigBackupService: neService.NewNeConfigBackup,
|
||||
neInfoService: neService.NewNeInfo,
|
||||
backupService: neDataService.NewBackup,
|
||||
count: 0,
|
||||
}
|
||||
|
||||
@@ -20,6 +22,7 @@ var NewProcessor = &NeConfigBackupProcessor{
|
||||
type NeConfigBackupProcessor struct {
|
||||
neConfigBackupService *neService.NeConfigBackup // 网元配置文件备份记录服务
|
||||
neInfoService *neService.NeInfo // 网元信息服务
|
||||
backupService *neDataService.Backup // 备份相关服务
|
||||
count int // 执行次数
|
||||
}
|
||||
|
||||
@@ -42,6 +45,7 @@ func (s *NeConfigBackupProcessor) Execute(data any) (any, error) {
|
||||
result[neTypeAndId] = err.Error()
|
||||
continue
|
||||
}
|
||||
|
||||
// 新增备份记录
|
||||
item := neModel.NeConfigBackup{
|
||||
NeType: neInfo.NeType,
|
||||
@@ -50,8 +54,18 @@ func (s *NeConfigBackupProcessor) Execute(data any) (any, error) {
|
||||
Path: zipFilePath,
|
||||
CreateBy: "system",
|
||||
}
|
||||
s.neConfigBackupService.Insert(item)
|
||||
result[neTypeAndId] = "ok"
|
||||
rows := s.neConfigBackupService.Insert(item)
|
||||
if rows <= 0 {
|
||||
result[neTypeAndId] = "failed"
|
||||
continue
|
||||
}
|
||||
|
||||
msg := "ok"
|
||||
// 上传到FTP服务器
|
||||
if err := s.backupService.FTPPushFile(zipFilePath, "ne_config"); err != nil {
|
||||
result[neTypeAndId] = msg + ", ftp err:" + err.Error()
|
||||
}
|
||||
result[neTypeAndId] = msg
|
||||
}
|
||||
|
||||
return result, nil
|
||||
|
||||
@@ -2,16 +2,17 @@ package processor
|
||||
|
||||
import (
|
||||
"be.ems/src/framework/cron"
|
||||
processorBackupExportTable "be.ems/src/modules/crontask/processor/backup_export_table"
|
||||
processorBackupExportUDM "be.ems/src/modules/crontask/processor/backup_export_udm"
|
||||
processorBackupRemoveFile "be.ems/src/modules/crontask/processor/backup_remove_file"
|
||||
processorDeleteAlarmRecord "be.ems/src/modules/crontask/processor/delete_alarm_record"
|
||||
processorDeleteDataRecord "be.ems/src/modules/crontask/processor/delete_data_record"
|
||||
processorDeleteKPIRecord "be.ems/src/modules/crontask/processor/delete_kpi_record"
|
||||
processorDeleteNeConfigBackup "be.ems/src/modules/crontask/processor/delete_ne_config_backup"
|
||||
"be.ems/src/modules/crontask/processor/exportTable"
|
||||
processorMonitorSysResource "be.ems/src/modules/crontask/processor/monitor_sys_resource"
|
||||
processorNeAlarmStateCheck "be.ems/src/modules/crontask/processor/ne_alarm_state_check"
|
||||
processorNeConfigBackup "be.ems/src/modules/crontask/processor/ne_config_backup"
|
||||
processorNeDataUDM "be.ems/src/modules/crontask/processor/ne_data_udm"
|
||||
"be.ems/src/modules/crontask/processor/removeFile"
|
||||
)
|
||||
|
||||
// InitCronQueue 初始定时任务队列
|
||||
@@ -20,7 +21,7 @@ func InitCronQueue() {
|
||||
cron.CreateQueue("monitor_sys_resource", processorMonitorSysResource.NewProcessor)
|
||||
// 网元-网元配置文件定期备份
|
||||
cron.CreateQueue("ne_config_backup", processorNeConfigBackup.NewProcessor)
|
||||
// 网元数据-UDM数据刷新同步
|
||||
// 网元数据-UDM用户数据同步
|
||||
cron.CreateQueue("ne_data_udm", processorNeDataUDM.NewProcessor)
|
||||
// 网元告警-状态检查
|
||||
cron.CreateQueue("ne_alarm_state_check", processorNeAlarmStateCheck.NewProcessor)
|
||||
@@ -34,6 +35,10 @@ func InitCronQueue() {
|
||||
// 删除-网元配置文件定期备份
|
||||
cron.CreateQueue("delete_ne_config_backup", processorDeleteNeConfigBackup.NewProcessor)
|
||||
|
||||
cron.CreateQueue("exportTable", exportTable.NewProcessor)
|
||||
cron.CreateQueue("removeFile", removeFile.NewProcessor)
|
||||
// 备份-导出数据表
|
||||
cron.CreateQueue("backup_export_table", processorBackupExportTable.NewProcessor)
|
||||
// 备份-删除备份目录下文件
|
||||
cron.CreateQueue("backup_remove_file", processorBackupRemoveFile.NewProcessor)
|
||||
// 备份-导出UDM用户数据
|
||||
cron.CreateQueue("backup_export_udm", processorBackupExportUDM.NewProcessor)
|
||||
}
|
||||
|
||||
@@ -1,159 +0,0 @@
|
||||
package removeFile
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"be.ems/lib/log"
|
||||
"be.ems/src/framework/cron"
|
||||
)
|
||||
|
||||
var NewProcessor = &BarProcessor{
|
||||
progress: 0,
|
||||
count: 0,
|
||||
}
|
||||
|
||||
// bar 队列任务处理
|
||||
type BarProcessor struct {
|
||||
// 任务进度
|
||||
progress int
|
||||
// 执行次数
|
||||
count int
|
||||
}
|
||||
|
||||
type BarParams struct {
|
||||
FilePath string `json:"filePath"` // file path
|
||||
MaxDays int `json:"maxDays"`
|
||||
MaxFiles *int `json:"maxFiles"` // keep max files
|
||||
MaxSize *int64 `json:"maxSize"`
|
||||
Extras string `json:"extras"` // extras condition for where
|
||||
}
|
||||
|
||||
type FileInfo struct {
|
||||
Path string
|
||||
Info os.FileInfo
|
||||
}
|
||||
|
||||
func (s *BarProcessor) Execute(data any) (any, error) {
|
||||
s.count++
|
||||
|
||||
options := data.(cron.JobData)
|
||||
sysJob := options.SysJob
|
||||
var params []BarParams
|
||||
|
||||
err := json.Unmarshal([]byte(sysJob.TargetParams), ¶ms)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result := []map[string]any{}
|
||||
for _, param := range params {
|
||||
res, _ := s.ExecuteOne(param)
|
||||
result = append(result, res)
|
||||
}
|
||||
|
||||
// 返回结果,用于记录执行结果
|
||||
return map[string]any{
|
||||
"result": result,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *BarProcessor) ExecuteOne(params BarParams) (map[string]any, error) {
|
||||
var maxFiles int = 0
|
||||
var maxSize int64 = 0
|
||||
if params.MaxFiles != nil {
|
||||
maxFiles = *params.MaxFiles
|
||||
}
|
||||
if params.MaxSize != nil {
|
||||
maxSize = int64(*params.MaxSize * 1024 * 1024)
|
||||
}
|
||||
files, err := getFiles(params.FilePath)
|
||||
if err != nil {
|
||||
return map[string]any{
|
||||
"msg": "failed",
|
||||
"err": err.Error(),
|
||||
}, err
|
||||
}
|
||||
|
||||
// 获取本地时区
|
||||
loc, err := time.LoadLocation("Local")
|
||||
if err != nil {
|
||||
return map[string]any{
|
||||
"msg": "failed",
|
||||
"err": err.Error(),
|
||||
}, err
|
||||
}
|
||||
cutoff := time.Now().In(loc).AddDate(0, 0, -params.MaxDays)
|
||||
|
||||
var oldFiles []FileInfo
|
||||
for _, file := range files {
|
||||
if file.Info.ModTime().Before(cutoff) {
|
||||
oldFiles = append(oldFiles, file)
|
||||
}
|
||||
}
|
||||
|
||||
// 按修改时间排序文件(最旧的在前)
|
||||
sort.Slice(oldFiles, func(i, j int) bool {
|
||||
return oldFiles[i].Info.ModTime().Before(oldFiles[j].Info.ModTime())
|
||||
})
|
||||
|
||||
deleted, errorDel := 0, 0
|
||||
|
||||
// 删除文件,直到满足文件总数不超过maxFiles个且总大小不超过maxSize的条件
|
||||
var totalSize int64
|
||||
for i, file := range oldFiles {
|
||||
if (maxFiles > 0 && i >= maxFiles) || (maxSize > 0 && totalSize+file.Info.Size() > maxSize) {
|
||||
break
|
||||
}
|
||||
err := os.Remove(file.Path)
|
||||
if err != nil {
|
||||
log.Error("Error deleting file:", file.Path, err)
|
||||
errorDel++
|
||||
continue
|
||||
}
|
||||
totalSize += file.Info.Size()
|
||||
deleted++
|
||||
}
|
||||
|
||||
// 如果仍然有超过maxFiles个文件或总大小超过maxSize,继续删除最旧的文件
|
||||
remainingFiles := files
|
||||
sort.Slice(remainingFiles, func(i, j int) bool {
|
||||
return remainingFiles[i].Info.ModTime().Before(remainingFiles[j].Info.ModTime())
|
||||
})
|
||||
|
||||
for (maxFiles > 0 && len(remainingFiles) > maxFiles) || (maxSize > 0 && totalSize > maxSize) {
|
||||
file := remainingFiles[0]
|
||||
err := os.Remove(file.Path)
|
||||
if err != nil {
|
||||
log.Error("Error deleting file:", file.Path, err)
|
||||
remainingFiles = remainingFiles[1:]
|
||||
continue
|
||||
}
|
||||
totalSize -= file.Info.Size()
|
||||
remainingFiles = remainingFiles[1:]
|
||||
}
|
||||
|
||||
// 返回结果,用于记录执行结果
|
||||
return map[string]any{
|
||||
"msg": "successed",
|
||||
"filePath": params.FilePath,
|
||||
"deleted": deleted,
|
||||
"errorDel": errorDel,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func getFiles(dir string) ([]FileInfo, error) {
|
||||
var files []FileInfo
|
||||
err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !info.IsDir() {
|
||||
files = append(files, FileInfo{Path: path, Info: info})
|
||||
}
|
||||
return nil
|
||||
})
|
||||
return files, err
|
||||
}
|
||||
@@ -50,7 +50,7 @@ func (s *MonitorController) Load(c *gin.Context) {
|
||||
}
|
||||
if err := c.ShouldBindQuery(&querys); err != nil {
|
||||
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||||
c.JSON(422, resp.CodeMsg(40422, errMsgs))
|
||||
c.JSON(422, resp.CodeMsg(422001, errMsgs))
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -48,13 +48,15 @@ func (s *SysCacheController) Info(c *gin.Context) {
|
||||
func (s SysCacheController) Names(c *gin.Context) {
|
||||
language := reqctx.AcceptLanguage(c)
|
||||
caches := []model.SysCache{
|
||||
model.NewNames(i18n.TKey(language, "cache.name.user"), constants.CACHE_LOGIN_TOKEN),
|
||||
model.NewNames(i18n.TKey(language, "cache.name.token"), constants.CACHE_TOKEN_DEVICE),
|
||||
model.NewNames(i18n.TKey(language, "cache.name.sys_config"), constants.CACHE_SYS_CONFIG),
|
||||
model.NewNames(i18n.TKey(language, "cache.name.sys_dict"), constants.CACHE_SYS_DICT),
|
||||
model.NewNames(i18n.TKey(language, "cache.name.captcha_codes"), constants.CACHE_CAPTCHA_CODE),
|
||||
model.NewNames(i18n.TKey(language, "cache.name.repeat_submit"), constants.CACHE_REPEAT_SUBMIT),
|
||||
model.NewNames(i18n.TKey(language, "cache.name.rate_limit"), constants.CACHE_RATE_LIMIT),
|
||||
model.NewNames(i18n.TKey(language, "cache.name.pwd_err_cnt"), constants.CACHE_PWD_ERR_COUNT),
|
||||
model.NewNames(i18n.TKey(language, "cache.name.oauth2_codes"), constants.CACHE_OAUTH2_CODE),
|
||||
model.NewNames(i18n.TKey(language, "cache.name.oauth2_devices"), constants.CACHE_OAUTH2_DEVICE),
|
||||
model.NewNames(i18n.TKey(language, "cache.name.i18n"), constants.CACHE_I18N),
|
||||
model.NewNames(i18n.TKey(language, "cache.name.ne_info"), constants.CACHE_NE_INFO),
|
||||
model.NewNames(i18n.TKey(language, "cache.name.ne_data"), constants.CACHE_NE_DATA),
|
||||
@@ -71,7 +73,7 @@ func (s SysCacheController) Keys(c *gin.Context) {
|
||||
}
|
||||
if err := c.ShouldBindQuery(&query); err != nil {
|
||||
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||||
c.JSON(422, resp.CodeMsg(40422, errMsgs))
|
||||
c.JSON(422, resp.CodeMsg(422001, errMsgs))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -94,7 +96,7 @@ func (s SysCacheController) Value(c *gin.Context) {
|
||||
}
|
||||
if err := c.ShouldBindQuery(&query); err != nil {
|
||||
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||||
c.JSON(422, resp.CodeMsg(40422, errMsgs))
|
||||
c.JSON(422, resp.CodeMsg(422001, errMsgs))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -163,10 +165,10 @@ func (s SysCacheController) CleanKeys(c *gin.Context) {
|
||||
}
|
||||
if err := c.ShouldBindQuery(&query); err != nil {
|
||||
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||||
c.JSON(422, resp.CodeMsg(40422, errMsgs))
|
||||
c.JSON(422, resp.CodeMsg(422001, errMsgs))
|
||||
return
|
||||
}
|
||||
if constants.CACHE_LOGIN_TOKEN == query.CacheName {
|
||||
if constants.CACHE_TOKEN_DEVICE == query.CacheName {
|
||||
c.JSON(200, resp.ErrMsg("Cannot delete user information cache"))
|
||||
return
|
||||
}
|
||||
@@ -194,7 +196,7 @@ func (s SysCacheController) CleanValue(c *gin.Context) {
|
||||
}
|
||||
if err := c.ShouldBindQuery(&query); err != nil {
|
||||
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||||
c.JSON(422, resp.CodeMsg(40422, errMsgs))
|
||||
c.JSON(422, resp.CodeMsg(422001, errMsgs))
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -64,7 +64,7 @@ func (s *SysJobController) Info(c *gin.Context) {
|
||||
language := reqctx.AcceptLanguage(c)
|
||||
jobId := parse.Number(c.Param("jobId"))
|
||||
if jobId <= 0 {
|
||||
c.JSON(400, resp.CodeMsg(40010, "bind err: jobId is empty"))
|
||||
c.JSON(422, resp.CodeMsg(422002, "bind err: jobId is empty"))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -87,11 +87,11 @@ func (s *SysJobController) Add(c *gin.Context) {
|
||||
var body model.SysJob
|
||||
if err := c.ShouldBindBodyWithJSON(&body); err != nil {
|
||||
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||||
c.JSON(422, resp.CodeMsg(40422, errMsgs))
|
||||
c.JSON(422, resp.CodeMsg(422001, errMsgs))
|
||||
return
|
||||
}
|
||||
if body.JobId > 0 {
|
||||
c.JSON(400, resp.CodeMsg(40010, "bind err: jobId not is empty"))
|
||||
c.JSON(422, resp.CodeMsg(422002, "bind err: jobId not is empty"))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -143,11 +143,11 @@ func (s *SysJobController) Edit(c *gin.Context) {
|
||||
var body model.SysJob
|
||||
if err := c.ShouldBindBodyWithJSON(&body); err != nil {
|
||||
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||||
c.JSON(422, resp.CodeMsg(40422, errMsgs))
|
||||
c.JSON(422, resp.CodeMsg(422001, errMsgs))
|
||||
return
|
||||
}
|
||||
if body.JobId <= 0 {
|
||||
c.JSON(400, resp.CodeMsg(40010, "bind err: jobId is empty"))
|
||||
c.JSON(422, resp.CodeMsg(422002, "bind err: jobId is empty"))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -229,7 +229,7 @@ func (s *SysJobController) Remove(c *gin.Context) {
|
||||
language := reqctx.AcceptLanguage(c)
|
||||
jobId := c.Param("jobId")
|
||||
if jobId == "" {
|
||||
c.JSON(400, resp.CodeMsg(40010, "bind err: jobId is empty"))
|
||||
c.JSON(422, resp.CodeMsg(422002, "bind err: jobId is empty"))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -261,7 +261,7 @@ func (s *SysJobController) Status(c *gin.Context) {
|
||||
}
|
||||
if err := c.ShouldBindBodyWithJSON(&body); err != nil {
|
||||
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||||
c.JSON(422, resp.CodeMsg(40422, errMsgs))
|
||||
c.JSON(422, resp.CodeMsg(422001, errMsgs))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -299,7 +299,7 @@ func (s *SysJobController) Run(c *gin.Context) {
|
||||
language := reqctx.AcceptLanguage(c)
|
||||
jobId := parse.Number(c.Param("jobId"))
|
||||
if jobId <= 0 {
|
||||
c.JSON(400, resp.CodeMsg(40010, "bind err: jobId is empty"))
|
||||
c.JSON(422, resp.CodeMsg(422002, "bind err: jobId is empty"))
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -73,7 +73,7 @@ func (s *SysJobLogController) List(c *gin.Context) {
|
||||
func (s *SysJobLogController) Info(c *gin.Context) {
|
||||
logId := parse.Number(c.Param("logId"))
|
||||
if logId <= 0 {
|
||||
c.JSON(400, resp.CodeMsg(40010, "bind err: logId is empty"))
|
||||
c.JSON(422, resp.CodeMsg(422002, "bind err: logId is empty"))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -92,7 +92,7 @@ func (s *SysJobLogController) Remove(c *gin.Context) {
|
||||
language := reqctx.AcceptLanguage(c)
|
||||
logId := c.Param("logId")
|
||||
if logId == "" {
|
||||
c.JSON(400, resp.CodeMsg(40010, "bind err: logId is empty"))
|
||||
c.JSON(422, resp.CodeMsg(422002, "bind err: logId is empty"))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -143,13 +143,6 @@ func (s *SysJobLogController) Export(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
// rows := s.sysJobLogService.SelectJobLogList(model.SysJobLog{})
|
||||
if len(rows) <= 0 {
|
||||
// 导出数据记录为空
|
||||
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.exportEmpty")))
|
||||
return
|
||||
}
|
||||
|
||||
// 闭包函数处理多语言
|
||||
converI18n := func(language string, arr *[]model.SysJobLog) {
|
||||
for i := range *arr {
|
||||
|
||||
@@ -46,7 +46,7 @@ func (s *SysUserOnlineController) List(c *gin.Context) {
|
||||
userName := c.Query("userName")
|
||||
|
||||
// 获取所有在线用户key
|
||||
keys, _ := redis.GetKeys("", constants.CACHE_LOGIN_TOKEN+":*")
|
||||
keys, _ := redis.GetKeys("", constants.CACHE_TOKEN_DEVICE+":*")
|
||||
|
||||
// 分批获取
|
||||
arr := make([]string, 0)
|
||||
@@ -69,13 +69,13 @@ func (s *SysUserOnlineController) List(c *gin.Context) {
|
||||
continue
|
||||
}
|
||||
|
||||
var tokenInfo token.TokenInfo
|
||||
err := json.Unmarshal([]byte(str), &tokenInfo)
|
||||
var info token.UserInfo
|
||||
err := json.Unmarshal([]byte(str), &info)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
onlineUser := s.sysUserOnlineService.TokenInfoToUserOnline(tokenInfo)
|
||||
onlineUser := s.sysUserOnlineService.UserInfoToUserOnline(info)
|
||||
if onlineUser.TokenID != "" {
|
||||
userOnlines = append(userOnlines, onlineUser)
|
||||
}
|
||||
@@ -122,15 +122,14 @@ func (s *SysUserOnlineController) List(c *gin.Context) {
|
||||
func (s SysUserOnlineController) Logout(c *gin.Context) {
|
||||
tokenIdStr := c.Param("tokenId")
|
||||
if tokenIdStr == "" || strings.Contains(tokenIdStr, "*") {
|
||||
c.JSON(400, resp.CodeMsg(40010, "bind err: tokenId is empty"))
|
||||
c.JSON(422, resp.CodeMsg(422002, "bind err: tokenId is empty"))
|
||||
return
|
||||
}
|
||||
|
||||
// 处理字符转id数组后去重
|
||||
ids := strings.Split(tokenIdStr, ",")
|
||||
uniqueIDs := parse.RemoveDuplicates(ids)
|
||||
uniqueIDs := parse.RemoveDuplicatesToArray(tokenIdStr, ",")
|
||||
for _, v := range uniqueIDs {
|
||||
key := constants.CACHE_LOGIN_TOKEN + ":" + v
|
||||
key := constants.CACHE_TOKEN_DEVICE + ":" + v
|
||||
if err := redis.Del("", key); err != nil {
|
||||
c.JSON(200, resp.ErrMsg(err.Error()))
|
||||
return
|
||||
|
||||
@@ -23,15 +23,14 @@ func Setup(router *gin.Engine) {
|
||||
monitorGroup := router.Group("/monitor")
|
||||
{
|
||||
monitorGroup.GET("/load",
|
||||
middleware.PreAuthorize(nil),
|
||||
middleware.AuthorizeUser(nil),
|
||||
controller.NewMonitor.Load,
|
||||
)
|
||||
}
|
||||
|
||||
// 服务器信息
|
||||
router.GET("/monitor/system",
|
||||
// middleware.PreAuthorize(map[string][]string{"hasPerms": {"monitor:system:info"}}),
|
||||
middleware.PreAuthorize(nil),
|
||||
middleware.AuthorizeUser(map[string][]string{"hasPerms": {"monitor:system:info"}}),
|
||||
controller.NewSystem.Info,
|
||||
)
|
||||
|
||||
@@ -39,11 +38,11 @@ func Setup(router *gin.Engine) {
|
||||
sysUserOnlineGroup := router.Group("/monitor/user-online")
|
||||
{
|
||||
sysUserOnlineGroup.GET("/list",
|
||||
middleware.PreAuthorize(map[string][]string{"hasPerms": {"monitor:online:list"}}),
|
||||
middleware.AuthorizeUser(map[string][]string{"hasPerms": {"monitor:online:list"}}),
|
||||
controller.NewSysUserOnline.List,
|
||||
)
|
||||
sysUserOnlineGroup.DELETE("/logout/:tokenId",
|
||||
middleware.PreAuthorize(map[string][]string{"hasPerms": {"monitor:online:logout"}}),
|
||||
middleware.AuthorizeUser(map[string][]string{"hasPerms": {"monitor:online:logout"}}),
|
||||
controller.NewSysUserOnline.Logout,
|
||||
)
|
||||
}
|
||||
@@ -52,32 +51,31 @@ func Setup(router *gin.Engine) {
|
||||
sysCacheGroup := router.Group("/monitor/cache")
|
||||
{
|
||||
sysCacheGroup.GET("",
|
||||
// middleware.PreAuthorize(map[string][]string{"hasPerms": {"monitor:cache:info"}}),
|
||||
middleware.PreAuthorize(nil),
|
||||
middleware.AuthorizeUser(map[string][]string{"hasPerms": {"monitor:cache:info"}}),
|
||||
controller.NewSysCache.Info,
|
||||
)
|
||||
sysCacheGroup.GET("/names",
|
||||
middleware.PreAuthorize(map[string][]string{"hasPerms": {"monitor:cache:list"}}),
|
||||
middleware.AuthorizeUser(map[string][]string{"hasPerms": {"monitor:cache:list"}}),
|
||||
controller.NewSysCache.Names,
|
||||
)
|
||||
sysCacheGroup.GET("/keys",
|
||||
middleware.PreAuthorize(map[string][]string{"hasPerms": {"monitor:cache:list"}}),
|
||||
middleware.AuthorizeUser(map[string][]string{"hasPerms": {"monitor:cache:list"}}),
|
||||
controller.NewSysCache.Keys,
|
||||
)
|
||||
sysCacheGroup.GET("/value",
|
||||
middleware.PreAuthorize(map[string][]string{"hasPerms": {"monitor:cache:query"}}),
|
||||
middleware.AuthorizeUser(map[string][]string{"hasPerms": {"monitor:cache:query"}}),
|
||||
controller.NewSysCache.Value,
|
||||
)
|
||||
sysCacheGroup.DELETE("/names",
|
||||
middleware.PreAuthorize(map[string][]string{"hasPerms": {"monitor:cache:remove"}}),
|
||||
middleware.AuthorizeUser(map[string][]string{"hasPerms": {"monitor:cache:remove"}}),
|
||||
controller.NewSysCache.CleanNames,
|
||||
)
|
||||
sysCacheGroup.DELETE("/keys",
|
||||
middleware.PreAuthorize(map[string][]string{"hasPerms": {"monitor:cache:remove"}}),
|
||||
middleware.AuthorizeUser(map[string][]string{"hasPerms": {"monitor:cache:remove"}}),
|
||||
controller.NewSysCache.CleanKeys,
|
||||
)
|
||||
sysCacheGroup.DELETE("/value",
|
||||
middleware.PreAuthorize(map[string][]string{"hasPerms": {"monitor:cache:remove"}}),
|
||||
middleware.AuthorizeUser(map[string][]string{"hasPerms": {"monitor:cache:remove"}}),
|
||||
controller.NewSysCache.CleanValue,
|
||||
)
|
||||
}
|
||||
@@ -86,26 +84,26 @@ func Setup(router *gin.Engine) {
|
||||
sysJobLogGroup := router.Group("/monitor/job/log")
|
||||
{
|
||||
sysJobLogGroup.GET("/list",
|
||||
middleware.PreAuthorize(map[string][]string{"hasPerms": {"monitor:job:list"}}),
|
||||
middleware.AuthorizeUser(map[string][]string{"hasPerms": {"monitor:job:list"}}),
|
||||
controller.NewSysJobLog.List,
|
||||
)
|
||||
sysJobLogGroup.GET("/:logId",
|
||||
middleware.PreAuthorize(map[string][]string{"hasPerms": {"monitor:job:query"}}),
|
||||
middleware.AuthorizeUser(map[string][]string{"hasPerms": {"monitor:job:query"}}),
|
||||
controller.NewSysJobLog.Info,
|
||||
)
|
||||
sysJobLogGroup.DELETE("/:logId",
|
||||
middleware.PreAuthorize(map[string][]string{"hasPerms": {"monitor:job:remove"}}),
|
||||
middleware.AuthorizeUser(map[string][]string{"hasPerms": {"monitor:job:remove"}}),
|
||||
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.sysJobLog", collectlogs.BUSINESS_TYPE_DELETE)),
|
||||
controller.NewSysJobLog.Remove,
|
||||
)
|
||||
sysJobLogGroup.DELETE("/clean",
|
||||
repeat.RepeatSubmit(5),
|
||||
middleware.PreAuthorize(map[string][]string{"hasPerms": {"monitor:job:remove"}}),
|
||||
middleware.AuthorizeUser(map[string][]string{"hasPerms": {"monitor:job:remove"}}),
|
||||
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.sysJobLog", collectlogs.BUSINESS_TYPE_CLEAN)),
|
||||
controller.NewSysJobLog.Clean,
|
||||
)
|
||||
sysJobLogGroup.GET("/export",
|
||||
middleware.PreAuthorize(map[string][]string{"hasPerms": {"monitor:job:export"}}),
|
||||
middleware.AuthorizeUser(map[string][]string{"hasPerms": {"monitor:job:export"}}),
|
||||
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.sysJobLog", collectlogs.BUSINESS_TYPE_EXPORT)),
|
||||
controller.NewSysJobLog.Export,
|
||||
)
|
||||
@@ -115,47 +113,47 @@ func Setup(router *gin.Engine) {
|
||||
sysJobGroup := router.Group("/monitor/job")
|
||||
{
|
||||
sysJobGroup.GET("/list",
|
||||
middleware.PreAuthorize(map[string][]string{"hasPerms": {"monitor:job:list"}}),
|
||||
middleware.AuthorizeUser(map[string][]string{"hasPerms": {"monitor:job:list"}}),
|
||||
controller.NewSysJob.List,
|
||||
)
|
||||
sysJobGroup.GET("/:jobId",
|
||||
middleware.PreAuthorize(map[string][]string{"hasPerms": {"monitor:job:query"}}),
|
||||
middleware.AuthorizeUser(map[string][]string{"hasPerms": {"monitor:job:query"}}),
|
||||
controller.NewSysJob.Info,
|
||||
)
|
||||
sysJobGroup.POST("",
|
||||
middleware.PreAuthorize(map[string][]string{"hasPerms": {"monitor:job:add"}}),
|
||||
middleware.AuthorizeUser(map[string][]string{"hasPerms": {"monitor:job:add"}}),
|
||||
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.sysJob", collectlogs.BUSINESS_TYPE_INSERT)),
|
||||
controller.NewSysJob.Add,
|
||||
)
|
||||
sysJobGroup.PUT("",
|
||||
middleware.PreAuthorize(map[string][]string{"hasPerms": {"monitor:job:edit"}}),
|
||||
middleware.AuthorizeUser(map[string][]string{"hasPerms": {"monitor:job:edit"}}),
|
||||
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.sysJob", collectlogs.BUSINESS_TYPE_UPDATE)),
|
||||
controller.NewSysJob.Edit,
|
||||
)
|
||||
sysJobGroup.DELETE("/:jobId",
|
||||
middleware.PreAuthorize(map[string][]string{"hasPerms": {"monitor:job:remove"}}),
|
||||
middleware.AuthorizeUser(map[string][]string{"hasPerms": {"monitor:job:remove"}}),
|
||||
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.sysJob", collectlogs.BUSINESS_TYPE_DELETE)),
|
||||
controller.NewSysJob.Remove,
|
||||
)
|
||||
sysJobGroup.PUT("/status",
|
||||
repeat.RepeatSubmit(5),
|
||||
middleware.PreAuthorize(map[string][]string{"hasPerms": {"monitor:job:changeStatus"}}),
|
||||
middleware.AuthorizeUser(map[string][]string{"hasPerms": {"monitor:job:changeStatus"}}),
|
||||
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.sysJob", collectlogs.BUSINESS_TYPE_UPDATE)),
|
||||
controller.NewSysJob.Status,
|
||||
)
|
||||
sysJobGroup.PUT("/run/:jobId",
|
||||
repeat.RepeatSubmit(10),
|
||||
middleware.PreAuthorize(map[string][]string{"hasPerms": {"monitor:job:changeStatus"}}),
|
||||
middleware.AuthorizeUser(map[string][]string{"hasPerms": {"monitor:job:changeStatus"}}),
|
||||
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.sysJob", collectlogs.BUSINESS_TYPE_UPDATE)),
|
||||
controller.NewSysJob.Run,
|
||||
)
|
||||
sysJobGroup.PUT("/reset",
|
||||
middleware.PreAuthorize(map[string][]string{"hasPerms": {"monitor:job:changeStatus"}}),
|
||||
middleware.AuthorizeUser(map[string][]string{"hasPerms": {"monitor:job:changeStatus"}}),
|
||||
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.sysJob", collectlogs.BUSINESS_TYPE_CLEAN)),
|
||||
controller.NewSysJob.ResetQueueJob,
|
||||
)
|
||||
sysJobGroup.GET("/export",
|
||||
middleware.PreAuthorize(map[string][]string{"hasPerms": {"monitor:job:export"}}),
|
||||
middleware.AuthorizeUser(map[string][]string{"hasPerms": {"monitor:job:export"}}),
|
||||
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.sysJob", collectlogs.BUSINESS_TYPE_EXPORT)),
|
||||
controller.NewSysJob.Export,
|
||||
)
|
||||
|
||||
@@ -11,23 +11,23 @@ var NewSysUserOnline = &SysUserOnline{}
|
||||
// SysUserOnline 在线用户 服务层处理
|
||||
type SysUserOnline struct{}
|
||||
|
||||
// TokenInfoToUserOnline 在线用户信息
|
||||
func (s SysUserOnline) TokenInfoToUserOnline(tokenInfo token.TokenInfo) model.SysUserOnline {
|
||||
if tokenInfo.UserId <= 0 {
|
||||
// UserInfoToUserOnline 在线用户信息
|
||||
func (s SysUserOnline) UserInfoToUserOnline(info token.UserInfo) model.SysUserOnline {
|
||||
if info.UserId <= 0 {
|
||||
return model.SysUserOnline{}
|
||||
}
|
||||
|
||||
sysUserOnline := model.SysUserOnline{
|
||||
TokenID: tokenInfo.UUID,
|
||||
UserName: tokenInfo.User.UserName,
|
||||
LoginIp: tokenInfo.LoginIp,
|
||||
LoginLocation: tokenInfo.LoginLocation,
|
||||
Browser: tokenInfo.Browser,
|
||||
OS: tokenInfo.OS,
|
||||
LoginTime: tokenInfo.LoginTime,
|
||||
TokenID: info.DeviceId,
|
||||
UserName: info.User.UserName,
|
||||
LoginIp: info.LoginIp,
|
||||
LoginLocation: info.LoginLocation,
|
||||
Browser: info.Browser,
|
||||
OS: info.OS,
|
||||
LoginTime: info.LoginTime,
|
||||
}
|
||||
if tokenInfo.User.DeptId > 0 {
|
||||
sysUserOnline.DeptName = tokenInfo.User.Dept.DeptName
|
||||
if info.User.DeptId > 0 {
|
||||
sysUserOnline.DeptName = info.User.Dept.DeptName
|
||||
}
|
||||
return sysUserOnline
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package controller
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"be.ems/src/framework/i18n"
|
||||
"be.ems/src/framework/reqctx"
|
||||
@@ -56,7 +57,7 @@ func (s AlarmController) List(c *gin.Context) {
|
||||
var query model.AlarmQuery
|
||||
if err := c.ShouldBindQuery(&query); err != nil {
|
||||
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||||
c.JSON(422, resp.CodeMsg(40422, errMsgs))
|
||||
c.JSON(422, resp.CodeMsg(422001, errMsgs))
|
||||
return
|
||||
}
|
||||
// 查询数据
|
||||
@@ -71,7 +72,7 @@ func (s AlarmController) Remove(c *gin.Context) {
|
||||
language := reqctx.AcceptLanguage(c)
|
||||
id := c.Param("id")
|
||||
if id == "" {
|
||||
c.JSON(400, resp.CodeMsg(40010, "bind err: id is empty"))
|
||||
c.JSON(422, resp.CodeMsg(422002, "bind err: id is empty"))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -101,7 +102,7 @@ func (s AlarmController) Clear(c *gin.Context) {
|
||||
}
|
||||
if err := c.ShouldBindBodyWithJSON(&body); err != nil {
|
||||
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||||
c.JSON(422, resp.CodeMsg(40422, errMsgs))
|
||||
c.JSON(422, resp.CodeMsg(422001, errMsgs))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -124,7 +125,7 @@ func (s AlarmController) Ack(c *gin.Context) {
|
||||
}
|
||||
if err := c.ShouldBindBodyWithJSON(&body); err != nil {
|
||||
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||||
c.JSON(422, resp.CodeMsg(40422, errMsgs))
|
||||
c.JSON(422, resp.CodeMsg(422001, errMsgs))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -136,3 +137,60 @@ func (s AlarmController) Ack(c *gin.Context) {
|
||||
}
|
||||
c.JSON(200, resp.OkData(rows))
|
||||
}
|
||||
|
||||
// 告警列表导出
|
||||
//
|
||||
// GET /export
|
||||
//
|
||||
// @Tags network_data/alarm
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param neType query string false "NE Type" Enums(IMS,AMF,AUSF,UDM,SMF,PCF,NSSF,NRF,UPF,MME,CBC,OMC,SGWC,SMSC)
|
||||
// @Param neId query string false "NE ID The actual record is the network element RmUid"
|
||||
// @Param neName query string false "NE Name"
|
||||
// @Param pvFlag query string false "PV Flag" Enums(PNF,VNF)
|
||||
// @Param alarmCode query string false "alarm status code"
|
||||
// @Param alarmType query string false "Alarm type Communication alarms=1, Equipment alarms=2, Processing faults=3, Environmental alarms=4, Quality of service alarms=5" Enums(1,2,3,4,5)
|
||||
// @Param alarmStatus query string false "Alarm status 0:clear, 1:active" Enums(0,1)
|
||||
// @Param origSeverity query string false "Alarm Type 1: Critical, 2: Major, 3: Minor, 4: Warning" Enums(1,2,3,4)
|
||||
// @Param sortField query string false "Sort fields, fill in result fields" default(event_time)
|
||||
// @Param sortOrder query string false "Sort by ascending or descending order, asc desc" default(asc)
|
||||
// @Param pageNum query number true "pageNum" default(1)
|
||||
// @Param pageSize query number true "pageSize" default(10)
|
||||
// @Success 200 {object} object "Response Results"
|
||||
// @Security TokenAuth
|
||||
// @Summary Alarm List Export
|
||||
// @Description Alarm List Export
|
||||
// @Router /neData/alarm/export [get]
|
||||
func (s AlarmController) Export(c *gin.Context) {
|
||||
language := reqctx.AcceptLanguage(c)
|
||||
// 查询结果,根据查询条件结果,单页最大值限制
|
||||
var query model.AlarmQuery
|
||||
if err := c.ShouldBindQuery(&query); err != nil {
|
||||
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||||
c.JSON(422, resp.CodeMsg(422001, errMsgs))
|
||||
return
|
||||
}
|
||||
// 限制导出数据集
|
||||
if query.PageSize > 10000 {
|
||||
query.PageSize = 10000
|
||||
}
|
||||
// 查询数据
|
||||
rows, total := s.alarmService.FindByPage(query)
|
||||
if total == 0 {
|
||||
// 导出数据记录为空
|
||||
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.exportEmpty")))
|
||||
return
|
||||
}
|
||||
|
||||
// 导出文件名称
|
||||
fileName := fmt.Sprintf("alarm_export_%d_%s_%d.xlsx", len(rows), query.AlarmStatus, time.Now().UnixMilli())
|
||||
// 导出数据表格
|
||||
saveFilePath, err := s.alarmService.ExportXlsx(rows, fileName, language, query.AlarmStatus)
|
||||
if err != nil {
|
||||
c.JSON(200, resp.ErrMsg(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
c.FileAttachment(saveFilePath, fileName)
|
||||
}
|
||||
|
||||
@@ -29,12 +29,12 @@ type AlarmForwardController struct {
|
||||
// @Tags network_data/alarm_forward
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param neType query string false "NE Type" Enums(IMS,AMF,AUSF,UDM,SMF,PCF,NSSF,NRF,UPF,MME,CBC,OMC,SGWC,SMSC) Enums(1,2,3,4)
|
||||
// @Param sortField query string false "Sort fields, fill in result fields" default(event_time)
|
||||
// @Param sortOrder query string false "Sort by ascending or descending order, asc desc" default(asc)
|
||||
// @Param pageNum query number true "pageNum" default(1)
|
||||
// @Param pageSize query number true "pageSize" default(10)
|
||||
// @Success 200 {object} object "Response Results"
|
||||
// @Param neType query string false "NE Type" Enums(IMS,AMF,AUSF,UDM,SMF,PCF,NSSF,NRF,UPF,MME,CBC,OMC,SGWC,SMSC) Enums(1,2,3,4)
|
||||
// @Param sortField query string false "Sort fields, fill in result fields" default(event_time)
|
||||
// @Param sortOrder query string false "Sort by ascending or descending order, asc desc" default(asc)
|
||||
// @Param pageNum query number true "pageNum" default(1)
|
||||
// @Param pageSize query number true "pageSize" default(10)
|
||||
// @Success 200 {object} object "Response Results"
|
||||
// @Security TokenAuth
|
||||
// @Summary Alarm Forward Log List
|
||||
// @Description Alarm Forward Log List
|
||||
@@ -43,7 +43,7 @@ func (s AlarmForwardController) List(c *gin.Context) {
|
||||
var query model.AlarmForwardLogQuery
|
||||
if err := c.ShouldBindQuery(&query); err != nil {
|
||||
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||||
c.JSON(422, resp.CodeMsg(40422, errMsgs))
|
||||
c.JSON(422, resp.CodeMsg(422001, errMsgs))
|
||||
return
|
||||
}
|
||||
// 查询数据
|
||||
|
||||
@@ -34,7 +34,7 @@ type AlarmLogController struct {
|
||||
// @Param neType query string false "NE Type" Enums(IMS,AMF,AUSF,UDM,SMF,PCF,NSSF,NRF,UPF,MME,CBC,OMC,SGWC,SMSC)
|
||||
// @Param neId query string false "NE ID The actual record is the network element RmUid"
|
||||
// @Param alarmLogType query string false "AlarmLog type Communication AlarmLogs=1, Equipment AlarmLogs=2, Processing faults=3, Environmental AlarmLogs=4, Quality of service AlarmLogs=5" Enums(1,2,3,4,5)
|
||||
// @Param alarmStatus query string false "Alarm status 0:clear, 1:active" Enums(0,1)
|
||||
// @Param alarmStatus query string false "Alarm status 0:clear, 1:active" Enums(0,1)
|
||||
// @Param origSeverity query string false "Alarm Type 1: Critical, 2: Major, 3: Minor, 4: Warning" Enums(1,2,3,4)
|
||||
// @Param sortField query string false "Sort fields, fill in result fields" default(event_time)
|
||||
// @Param sortOrder query string false "Sort by ascending or descending order, asc desc" default(asc)
|
||||
@@ -49,7 +49,7 @@ func (s AlarmLogController) List(c *gin.Context) {
|
||||
var query model.AlarmLogQuery
|
||||
if err := c.ShouldBindQuery(&query); err != nil {
|
||||
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||||
c.JSON(422, resp.CodeMsg(40422, errMsgs))
|
||||
c.JSON(422, resp.CodeMsg(422001, errMsgs))
|
||||
return
|
||||
}
|
||||
// 查询数据
|
||||
@@ -67,7 +67,7 @@ func (s AlarmLogController) List(c *gin.Context) {
|
||||
// @Param neType query string false "NE Type" Enums(IMS,AMF,AUSF,UDM,SMF,PCF,NSSF,NRF,UPF,MME,CBC,OMC,SGWC,SMSC)
|
||||
// @Param neId query string false "NE ID The actual record is the network element RmUid"
|
||||
// @Param alarmLogType query string false "AlarmLog type Communication AlarmLogs=1, Equipment AlarmLogs=2, Processing faults=3, Environmental AlarmLogs=4, Quality of service AlarmLogs=5" Enums(1,2,3,4,5)
|
||||
// @Param alarmStatus query string false "Alarm status 0:clear, 1:active" Enums(0,1)
|
||||
// @Param alarmStatus query string false "Alarm status 0:clear, 1:active" Enums(0,1)
|
||||
// @Param origSeverity query string false "Alarm Type 1: Critical, 2: Major, 3: Minor, 4: Warning" Enums(1,2,3,4)
|
||||
// @Param sortField query string false "Sort fields, fill in result fields" default(event_time)
|
||||
// @Param sortOrder query string false "Sort by ascending or descending order, asc desc" default(asc)
|
||||
@@ -82,7 +82,7 @@ func (s AlarmLogController) Event(c *gin.Context) {
|
||||
var query model.AlarmEventQuery
|
||||
if err := c.ShouldBindQuery(&query); err != nil {
|
||||
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||||
c.JSON(422, resp.CodeMsg(40422, errMsgs))
|
||||
c.JSON(422, resp.CodeMsg(422001, errMsgs))
|
||||
return
|
||||
}
|
||||
// 查询数据
|
||||
|
||||
101
src/modules/network_data/controller/all_backup.go
Normal file
101
src/modules/network_data/controller/all_backup.go
Normal file
@@ -0,0 +1,101 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"be.ems/src/framework/reqctx"
|
||||
"be.ems/src/framework/resp"
|
||||
"be.ems/src/modules/network_data/model"
|
||||
"be.ems/src/modules/network_data/service"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// 实例化控制层 BackupController 结构体
|
||||
var NewBackup = &BackupController{
|
||||
backupService: service.NewBackup,
|
||||
}
|
||||
|
||||
// 备份数据
|
||||
//
|
||||
// PATH /backup
|
||||
type BackupController struct {
|
||||
backupService *service.Backup // 备份相关服务
|
||||
}
|
||||
|
||||
// 备份文件-更新FTP配置
|
||||
//
|
||||
// PUT /ftp
|
||||
func (s BackupController) FTPUpdate(c *gin.Context) {
|
||||
var body model.BackupDataFTP
|
||||
if err := c.ShouldBindBodyWithJSON(&body); err != nil {
|
||||
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||||
c.JSON(422, resp.CodeMsg(422001, errMsgs))
|
||||
return
|
||||
}
|
||||
|
||||
byteData, err := json.Marshal(body)
|
||||
if err != nil {
|
||||
c.JSON(200, resp.ErrMsg(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
up := s.backupService.FTPConfigUpdate(string(byteData), reqctx.LoginUserToUserName(c))
|
||||
if up <= 0 {
|
||||
c.JSON(200, resp.ErrMsg("update failed"))
|
||||
return
|
||||
}
|
||||
c.JSON(200, resp.Ok(nil))
|
||||
}
|
||||
|
||||
// 备份文件-获取FTP配置
|
||||
//
|
||||
// GET /ftp
|
||||
func (s BackupController) FTPInfo(c *gin.Context) {
|
||||
info := s.backupService.FTPConfigInfo()
|
||||
c.JSON(200, resp.OkData(info))
|
||||
}
|
||||
|
||||
// 备份文件-文件FTP发送
|
||||
//
|
||||
// POST /ftp
|
||||
func (s BackupController) FTPPush(c *gin.Context) {
|
||||
var body struct {
|
||||
Path string `form:"path" binding:"required"` // 路径必须是 BACKUP_DIR 开头的路径
|
||||
Filename string `form:"fileName" binding:"required"`
|
||||
Tag string `form:"tag" binding:"required"` // 标签,用于区分不同的备份文件
|
||||
}
|
||||
if err := c.ShouldBindBodyWithJSON(&body); err != nil {
|
||||
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||||
c.JSON(422, resp.CodeMsg(422001, errMsgs))
|
||||
return
|
||||
}
|
||||
// 判断路径是否合法
|
||||
if !strings.HasPrefix(body.Path, s.backupService.BACKUP_DIR) {
|
||||
c.JSON(200, resp.ErrMsg("operation path is not within the allowed range"))
|
||||
return
|
||||
}
|
||||
|
||||
// 判断文件是否存在
|
||||
localFilePath := filepath.Join(body.Path, body.Filename)
|
||||
if runtime.GOOS == "windows" {
|
||||
localFilePath = fmt.Sprintf("C:%s", localFilePath)
|
||||
}
|
||||
if _, err := os.Stat(localFilePath); os.IsNotExist(err) {
|
||||
c.JSON(200, resp.ErrMsg("file does not exist"))
|
||||
return
|
||||
}
|
||||
|
||||
// 发送文件
|
||||
err := s.backupService.FTPPushFile(localFilePath, body.Tag)
|
||||
if err != nil {
|
||||
c.JSON(200, resp.ErrMsg(err.Error()))
|
||||
return
|
||||
}
|
||||
c.JSON(200, resp.Ok(nil))
|
||||
}
|
||||
@@ -49,7 +49,7 @@ func (s KPIController) KPIData(c *gin.Context) {
|
||||
var querys model.KPIQuery
|
||||
if err := c.ShouldBindQuery(&querys); err != nil {
|
||||
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||||
c.JSON(422, resp.CodeMsg(40422, errMsgs))
|
||||
c.JSON(422, resp.CodeMsg(422001, errMsgs))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -82,7 +82,7 @@ func (s KPIController) KPIData(c *gin.Context) {
|
||||
func (s KPIController) KPITitle(c *gin.Context) {
|
||||
neType := c.Query("neType")
|
||||
if neType == "" {
|
||||
c.JSON(400, resp.CodeMsg(40010, "bind err: neType is empty"))
|
||||
c.JSON(422, resp.CodeMsg(422002, "bind err: neType is empty"))
|
||||
return
|
||||
}
|
||||
kpiTitles := s.kpiReportService.FindTitle(neType)
|
||||
|
||||
@@ -53,7 +53,7 @@ func (s NBStateController) List(c *gin.Context) {
|
||||
var query model.NBStateQuery
|
||||
if err := c.ShouldBindQuery(&query); err != nil {
|
||||
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||||
c.JSON(422, resp.CodeMsg(40422, errMsgs))
|
||||
c.JSON(422, resp.CodeMsg(422001, errMsgs))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -89,7 +89,7 @@ func (s NBStateController) Export(c *gin.Context) {
|
||||
var querys model.NBStateQuery
|
||||
if err := c.ShouldBindBodyWithJSON(&querys); err != nil {
|
||||
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||||
c.JSON(422, resp.CodeMsg(40422, errMsgs))
|
||||
c.JSON(422, resp.CodeMsg(422001, errMsgs))
|
||||
return
|
||||
}
|
||||
// 限制导出数据集
|
||||
|
||||
@@ -52,7 +52,7 @@ func (s *AMFController) UEList(c *gin.Context) {
|
||||
var querys model.UEEventAMFQuery
|
||||
if err := c.ShouldBindQuery(&querys); err != nil {
|
||||
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||||
c.JSON(422, resp.CodeMsg(40422, errMsgs))
|
||||
c.JSON(422, resp.CodeMsg(422001, errMsgs))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -86,7 +86,7 @@ func (s *AMFController) UERemove(c *gin.Context) {
|
||||
language := reqctx.AcceptLanguage(c)
|
||||
id := c.Param("id")
|
||||
if id == "" {
|
||||
c.JSON(400, resp.CodeMsg(40010, "bind err: id is empty"))
|
||||
c.JSON(422, resp.CodeMsg(422002, "bind err: id is empty"))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -126,7 +126,7 @@ func (s *AMFController) UEExport(c *gin.Context) {
|
||||
var querys model.UEEventAMFQuery
|
||||
if err := c.ShouldBindBodyWithJSON(&querys); err != nil {
|
||||
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||||
c.JSON(422, resp.CodeMsg(40422, errMsgs))
|
||||
c.JSON(422, resp.CodeMsg(422001, errMsgs))
|
||||
return
|
||||
}
|
||||
// 限制导出数据集
|
||||
@@ -181,7 +181,7 @@ func (s *AMFController) NbInfoList(c *gin.Context) {
|
||||
}
|
||||
if err := c.ShouldBindQuery(&query); err != nil {
|
||||
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||||
c.JSON(422, resp.CodeMsg(40422, errMsgs))
|
||||
c.JSON(422, resp.CodeMsg(422001, errMsgs))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -221,7 +221,7 @@ func (s *AMFController) NbStateList(c *gin.Context) {
|
||||
language := reqctx.AcceptLanguage(c)
|
||||
neId := c.Query("neId")
|
||||
if neId == "" {
|
||||
c.JSON(400, resp.CodeMsg(40010, "bind err: neId is empty"))
|
||||
c.JSON(422, resp.CodeMsg(422002, "bind err: neId is empty"))
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ func (s *IMSController) CDRList(c *gin.Context) {
|
||||
var querys model.CDREventIMSQuery
|
||||
if err := c.ShouldBindQuery(&querys); err != nil {
|
||||
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||||
c.JSON(422, resp.CodeMsg(40422, errMsgs))
|
||||
c.JSON(422, resp.CodeMsg(422001, errMsgs))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -87,7 +87,7 @@ func (s *IMSController) CDRRemove(c *gin.Context) {
|
||||
language := reqctx.AcceptLanguage(c)
|
||||
id := c.Param("id")
|
||||
if id == "" {
|
||||
c.JSON(400, resp.CodeMsg(40010, "bind err: id is empty"))
|
||||
c.JSON(422, resp.CodeMsg(442002, "bind err: id is empty"))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -127,7 +127,7 @@ func (s *IMSController) CDRExport(c *gin.Context) {
|
||||
var querys model.CDREventIMSQuery
|
||||
if err := c.ShouldBindBodyWithJSON(&querys); err != nil {
|
||||
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||||
c.JSON(422, resp.CodeMsg(40422, errMsgs))
|
||||
c.JSON(422, resp.CodeMsg(422001, errMsgs))
|
||||
return
|
||||
}
|
||||
// 限制导出数据集
|
||||
@@ -177,7 +177,7 @@ func (s *IMSController) UeSessionNum(c *gin.Context) {
|
||||
language := reqctx.AcceptLanguage(c)
|
||||
neId := c.Query("neId")
|
||||
if neId == "" {
|
||||
c.JSON(400, resp.CodeMsg(40010, "bind err: neId is empty"))
|
||||
c.JSON(422, resp.CodeMsg(422002, "bind err: neId is empty"))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -222,7 +222,7 @@ func (s *IMSController) UeSessionList(c *gin.Context) {
|
||||
}
|
||||
if err := c.ShouldBindQuery(&query); err != nil {
|
||||
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||||
c.JSON(422, resp.CodeMsg(40422, errMsgs))
|
||||
c.JSON(422, resp.CodeMsg(422001, errMsgs))
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ func (s *MMEController) UEList(c *gin.Context) {
|
||||
var querys model.UEEventMMEQuery
|
||||
if err := c.ShouldBindQuery(&querys); err != nil {
|
||||
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||||
c.JSON(422, resp.CodeMsg(40422, errMsgs))
|
||||
c.JSON(422, resp.CodeMsg(422001, errMsgs))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -86,7 +86,7 @@ func (s *MMEController) UERemove(c *gin.Context) {
|
||||
language := reqctx.AcceptLanguage(c)
|
||||
id := c.Param("id")
|
||||
if id == "" {
|
||||
c.JSON(400, resp.CodeMsg(40010, "bind err: id is empty"))
|
||||
c.JSON(422, resp.CodeMsg(422002, "bind err: id is empty"))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -126,7 +126,7 @@ func (s *MMEController) UEExport(c *gin.Context) {
|
||||
var querys model.UEEventMMEQuery
|
||||
if err := c.ShouldBindBodyWithJSON(&querys); err != nil {
|
||||
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||||
c.JSON(422, resp.CodeMsg(40422, errMsgs))
|
||||
c.JSON(422, resp.CodeMsg(422001, errMsgs))
|
||||
return
|
||||
}
|
||||
// 限制导出数据集
|
||||
@@ -181,7 +181,7 @@ func (s *MMEController) NbInfoList(c *gin.Context) {
|
||||
}
|
||||
if err := c.ShouldBindQuery(&query); err != nil {
|
||||
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||||
c.JSON(422, resp.CodeMsg(40422, errMsgs))
|
||||
c.JSON(422, resp.CodeMsg(422001, errMsgs))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -221,7 +221,7 @@ func (s *MMEController) NbStateList(c *gin.Context) {
|
||||
language := reqctx.AcceptLanguage(c)
|
||||
neId := c.Query("neId")
|
||||
if neId == "" {
|
||||
c.JSON(400, resp.CodeMsg(40010, "bind err: neId is empty"))
|
||||
c.JSON(422, resp.CodeMsg(422002, "bind err: neId is empty"))
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ func (s *SGWCController) CDRList(c *gin.Context) {
|
||||
var querys model.CDREventSGWCQuery
|
||||
if err := c.ShouldBindQuery(&querys); err != nil {
|
||||
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||||
c.JSON(422, resp.CodeMsg(40422, errMsgs))
|
||||
c.JSON(422, resp.CodeMsg(422001, errMsgs))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -87,7 +87,7 @@ func (s *SGWCController) CDRRemove(c *gin.Context) {
|
||||
language := reqctx.AcceptLanguage(c)
|
||||
id := c.Param("id")
|
||||
if id == "" {
|
||||
c.JSON(400, resp.CodeMsg(40010, "bind err: id is empty"))
|
||||
c.JSON(422, resp.CodeMsg(422002, "bind err: id is empty"))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -127,7 +127,7 @@ func (s *SGWCController) CDRExport(c *gin.Context) {
|
||||
var querys model.CDREventSGWCQuery
|
||||
if err := c.ShouldBindBodyWithJSON(&querys); err != nil {
|
||||
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||||
c.JSON(422, resp.CodeMsg(40422, errMsgs))
|
||||
c.JSON(422, resp.CodeMsg(422001, errMsgs))
|
||||
return
|
||||
}
|
||||
// 限制导出数据集
|
||||
|
||||
@@ -55,7 +55,7 @@ func (s *SMFController) CDRList(c *gin.Context) {
|
||||
var querys model.CDREventSMFQuery
|
||||
if err := c.ShouldBindQuery(&querys); err != nil {
|
||||
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||||
c.JSON(422, resp.CodeMsg(40422, errMsgs))
|
||||
c.JSON(422, resp.CodeMsg(422001, errMsgs))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -89,7 +89,7 @@ func (s *SMFController) CDRRemove(c *gin.Context) {
|
||||
language := reqctx.AcceptLanguage(c)
|
||||
id := c.Param("id")
|
||||
if id == "" {
|
||||
c.JSON(400, resp.CodeMsg(40010, "bind err: id is empty"))
|
||||
c.JSON(422, resp.CodeMsg(422002, "bind err: id is empty"))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -129,7 +129,7 @@ func (s *SMFController) CDRExport(c *gin.Context) {
|
||||
var querys model.CDREventSMFQuery
|
||||
if err := c.ShouldBindBodyWithJSON(&querys); err != nil {
|
||||
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||||
c.JSON(422, resp.CodeMsg(40422, errMsgs))
|
||||
c.JSON(422, resp.CodeMsg(422001, errMsgs))
|
||||
return
|
||||
}
|
||||
// 限制导出数据集
|
||||
@@ -181,7 +181,8 @@ func (s *SMFController) SubUserNum(c *gin.Context) {
|
||||
NeId string `form:"neId" binding:"required"`
|
||||
}
|
||||
if err := c.ShouldBindQuery(&query); err != nil {
|
||||
c.JSON(400, resp.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
|
||||
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||||
c.JSON(422, resp.CodeMsg(422001, errMsgs))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -229,7 +230,8 @@ func (s *SMFController) SubUserList(c *gin.Context) {
|
||||
PageNum string `form:"pageNum"`
|
||||
}
|
||||
if err := c.ShouldBindQuery(&query); err != nil {
|
||||
c.JSON(400, resp.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
|
||||
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||||
c.JSON(422, resp.CodeMsg(422001, errMsgs))
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ func (s *SMSCController) CDRList(c *gin.Context) {
|
||||
var querys model.CDREventSMSCQuery
|
||||
if err := c.ShouldBindQuery(&querys); err != nil {
|
||||
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||||
c.JSON(422, resp.CodeMsg(40422, errMsgs))
|
||||
c.JSON(422, resp.CodeMsg(422001, errMsgs))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -86,7 +86,7 @@ func (s *SMSCController) CDRRemove(c *gin.Context) {
|
||||
language := reqctx.AcceptLanguage(c)
|
||||
id := c.Param("id")
|
||||
if id == "" {
|
||||
c.JSON(400, resp.CodeMsg(40010, "bind err: id is empty"))
|
||||
c.JSON(422, resp.CodeMsg(422002, "bind err: id is empty"))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -126,7 +126,7 @@ func (s *SMSCController) CDRExport(c *gin.Context) {
|
||||
var querys model.CDREventSMSCQuery
|
||||
if err := c.ShouldBindBodyWithJSON(&querys); err != nil {
|
||||
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||||
c.JSON(422, resp.CodeMsg(40422, errMsgs))
|
||||
c.JSON(422, resp.CodeMsg(422001, errMsgs))
|
||||
return
|
||||
}
|
||||
// 限制导出数据集
|
||||
|
||||
@@ -49,10 +49,9 @@ type UDMAuthController struct {
|
||||
// @Description UDM Authenticated User Data List Refresh Synchronization Latest
|
||||
// @Router /neData/udm/auth/resetData/{neId} [put]
|
||||
func (s *UDMAuthController) ResetData(c *gin.Context) {
|
||||
language := reqctx.AcceptLanguage(c)
|
||||
neId := c.Param("neId")
|
||||
if neId == "" {
|
||||
c.JSON(400, resp.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
|
||||
c.JSON(422, resp.CodeMsg(422002, "bind err: neId is empty"))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -101,7 +100,7 @@ func (s *UDMAuthController) Info(c *gin.Context) {
|
||||
neId := c.Param("neId")
|
||||
imsi := c.Param("imsi")
|
||||
if neId == "" || imsi == "" {
|
||||
c.JSON(400, resp.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
|
||||
c.JSON(422, resp.CodeMsg(422002, "bind err: neId/imsi is empty"))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -156,14 +155,18 @@ func (s *UDMAuthController) Add(c *gin.Context) {
|
||||
language := reqctx.AcceptLanguage(c)
|
||||
neId := c.Param("neId")
|
||||
if neId == "" {
|
||||
c.JSON(400, resp.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
|
||||
c.JSON(422, resp.CodeMsg(422002, "bind err: neId is empty"))
|
||||
return
|
||||
}
|
||||
|
||||
var body model.UDMAuthUser
|
||||
err := c.ShouldBindBodyWithJSON(&body)
|
||||
if err != nil || body.IMSI == "" {
|
||||
c.JSON(400, resp.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
|
||||
if err := c.ShouldBindBodyWithJSON(&body); err != nil {
|
||||
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||||
c.JSON(422, resp.CodeMsg(422001, errMsgs))
|
||||
return
|
||||
}
|
||||
if body.IMSI == "" {
|
||||
c.JSON(422, resp.CodeMsg(422002, "bind err: imsi is empty"))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -217,14 +220,18 @@ func (s *UDMAuthController) Adds(c *gin.Context) {
|
||||
neId := c.Param("neId")
|
||||
num := c.Param("num")
|
||||
if neId == "" || num == "" {
|
||||
c.JSON(400, resp.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
|
||||
c.JSON(422, resp.CodeMsg(422002, "bind err: neId/num is empty"))
|
||||
return
|
||||
}
|
||||
|
||||
var body model.UDMAuthUser
|
||||
err := c.ShouldBindBodyWithJSON(&body)
|
||||
if err != nil || body.IMSI == "" {
|
||||
c.JSON(400, resp.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
|
||||
if err := c.ShouldBindBodyWithJSON(&body); err != nil {
|
||||
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||||
c.JSON(422, resp.CodeMsg(422001, errMsgs))
|
||||
return
|
||||
}
|
||||
if body.IMSI == "" {
|
||||
c.JSON(422, resp.CodeMsg(422002, "bind err: imsi is empty"))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -276,14 +283,18 @@ func (s *UDMAuthController) Edit(c *gin.Context) {
|
||||
language := reqctx.AcceptLanguage(c)
|
||||
neId := c.Param("neId")
|
||||
if neId == "" {
|
||||
c.JSON(400, resp.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
|
||||
c.JSON(422, resp.CodeMsg(422002, "bind err: neId is empty"))
|
||||
return
|
||||
}
|
||||
|
||||
var body model.UDMAuthUser
|
||||
err := c.ShouldBindBodyWithJSON(&body)
|
||||
if err != nil || body.IMSI == "" {
|
||||
c.JSON(400, resp.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
|
||||
if err := c.ShouldBindBodyWithJSON(&body); err != nil {
|
||||
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||||
c.JSON(422, resp.CodeMsg(422001, errMsgs))
|
||||
return
|
||||
}
|
||||
if body.IMSI == "" {
|
||||
c.JSON(422, resp.CodeMsg(422002, "bind err: imsi is empty"))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -336,7 +347,7 @@ func (s *UDMAuthController) Remove(c *gin.Context) {
|
||||
neId := c.Param("neId")
|
||||
imsi := c.Param("imsi")
|
||||
if neId == "" || imsi == "" {
|
||||
c.JSON(400, resp.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
|
||||
c.JSON(422, resp.CodeMsg(422002, "bind err: neId/imsi is empty"))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -402,7 +413,7 @@ func (s *UDMAuthController) Removes(c *gin.Context) {
|
||||
imsi := c.Param("imsi")
|
||||
num := c.Param("num")
|
||||
if neId == "" || imsi == "" || num == "" {
|
||||
c.JSON(400, resp.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
|
||||
c.JSON(422, resp.CodeMsg(422002, "bind err: neId/imsi/num is empty"))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -458,7 +469,7 @@ func (s *UDMAuthController) Export(c *gin.Context) {
|
||||
neId := c.Query("neId")
|
||||
fileType := c.Query("type")
|
||||
if neId == "" {
|
||||
c.JSON(400, resp.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
|
||||
c.JSON(422, resp.CodeMsg(422002, "bind err: neId is empty"))
|
||||
return
|
||||
}
|
||||
if !(fileType == "csv" || fileType == "txt") {
|
||||
@@ -497,8 +508,7 @@ func (s *UDMAuthController) Export(c *gin.Context) {
|
||||
data = append(data, []string{v.IMSI, v.Ki, v.AlgoIndex, v.Amf, opc})
|
||||
}
|
||||
// 输出到文件
|
||||
err := file.WriterFileCSV(data, filePath)
|
||||
if err != nil {
|
||||
if err := file.WriterFileCSV(data, filePath); err != nil {
|
||||
c.JSON(200, resp.ErrMsg(err.Error()))
|
||||
return
|
||||
}
|
||||
@@ -515,7 +525,6 @@ func (s *UDMAuthController) Export(c *gin.Context) {
|
||||
data = append(data, []string{v.IMSI, v.Ki, v.AlgoIndex, v.Amf, opc})
|
||||
}
|
||||
// 输出到文件
|
||||
|
||||
if err := file.WriterFileTXT(data, ",", filePath); err != nil {
|
||||
c.JSON(200, resp.ErrMsg(err.Error()))
|
||||
return
|
||||
@@ -548,7 +557,7 @@ func (s *UDMAuthController) Import(c *gin.Context) {
|
||||
}
|
||||
if err := c.ShouldBindBodyWithJSON(&body); err != nil {
|
||||
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||||
c.JSON(422, resp.CodeMsg(40422, errMsgs))
|
||||
c.JSON(422, resp.CodeMsg(422001, errMsgs))
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -48,10 +48,9 @@ type UDMSubController struct {
|
||||
// @Description UDM Subscriber User Reload Data
|
||||
// @Router /neData/udm/sub/resetData/{neId} [put]
|
||||
func (s *UDMSubController) ResetData(c *gin.Context) {
|
||||
language := reqctx.AcceptLanguage(c)
|
||||
neId := c.Param("neId")
|
||||
if neId == "" {
|
||||
c.JSON(400, resp.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
|
||||
c.JSON(422, resp.CodeMsg(422002, "bind err: neId is empty"))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -101,7 +100,7 @@ func (s *UDMSubController) Info(c *gin.Context) {
|
||||
neId := c.Param("neId")
|
||||
imsi := c.Param("imsi")
|
||||
if neId == "" || imsi == "" {
|
||||
c.JSON(400, resp.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
|
||||
c.JSON(422, resp.CodeMsg(422002, "bind err: neId or imsi is empty"))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -156,18 +155,18 @@ func (s *UDMSubController) Add(c *gin.Context) {
|
||||
language := reqctx.AcceptLanguage(c)
|
||||
neId := c.Param("neId")
|
||||
if neId == "" {
|
||||
c.JSON(400, resp.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
|
||||
c.JSON(422, resp.CodeMsg(422002, "bind err: neId is empty"))
|
||||
return
|
||||
}
|
||||
|
||||
var body model.UDMSubUser
|
||||
if err := c.ShouldBindBodyWithJSON(&body); err != nil {
|
||||
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||||
c.JSON(422, resp.CodeMsg(40422, errMsgs))
|
||||
c.JSON(422, resp.CodeMsg(422001, errMsgs))
|
||||
return
|
||||
}
|
||||
if len(body.IMSI) != 15 {
|
||||
c.JSON(400, resp.CodeMsg(40010, "bind err: IMSI length is not 15 bits"))
|
||||
c.JSON(422, resp.CodeMsg(422002, "bind err: IMSI length is not 15 bits"))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -222,18 +221,18 @@ func (s *UDMSubController) Adds(c *gin.Context) {
|
||||
neId := c.Param("neId")
|
||||
num := c.Param("num")
|
||||
if neId == "" || num == "" {
|
||||
c.JSON(400, resp.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
|
||||
c.JSON(422, resp.CodeMsg(422002, "bind err: neId/num is empty"))
|
||||
return
|
||||
}
|
||||
|
||||
var body model.UDMSubUser
|
||||
if err := c.ShouldBindBodyWithJSON(&body); err != nil {
|
||||
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||||
c.JSON(422, resp.CodeMsg(40422, errMsgs))
|
||||
c.JSON(422, resp.CodeMsg(422001, errMsgs))
|
||||
return
|
||||
}
|
||||
if len(body.IMSI) != 15 {
|
||||
c.JSON(400, resp.CodeMsg(40010, "bind err: IMSI length is not 15 bits"))
|
||||
c.JSON(422, resp.CodeMsg(422002, "bind err: IMSI length is not 15 bits"))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -288,18 +287,18 @@ func (s *UDMSubController) Edit(c *gin.Context) {
|
||||
language := reqctx.AcceptLanguage(c)
|
||||
neId := c.Param("neId")
|
||||
if neId == "" {
|
||||
c.JSON(400, resp.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
|
||||
c.JSON(422, resp.CodeMsg(422002, "bind err: neId is empty"))
|
||||
return
|
||||
}
|
||||
|
||||
var body model.UDMSubUser
|
||||
if err := c.ShouldBindBodyWithJSON(&body); err != nil {
|
||||
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||||
c.JSON(422, resp.CodeMsg(40422, errMsgs))
|
||||
c.JSON(422, resp.CodeMsg(422001, errMsgs))
|
||||
return
|
||||
}
|
||||
if len(body.IMSI) != 15 {
|
||||
c.JSON(400, resp.CodeMsg(40010, "bind err: IMSI length is not 15 bits"))
|
||||
c.JSON(422, resp.CodeMsg(422002, "bind err: IMSI length is not 15 bits"))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -353,7 +352,7 @@ func (s *UDMSubController) Remove(c *gin.Context) {
|
||||
neId := c.Param("neId")
|
||||
imsi := c.Param("imsi")
|
||||
if neId == "" || len(imsi) < 15 {
|
||||
c.JSON(400, resp.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
|
||||
c.JSON(422, resp.CodeMsg(422002, "bind err: neId/imsi is empty"))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -419,7 +418,7 @@ func (s *UDMSubController) Removes(c *gin.Context) {
|
||||
imsi := c.Param("imsi")
|
||||
num := c.Param("num")
|
||||
if neId == "" || len(imsi) < 15 || num == "" {
|
||||
c.JSON(400, resp.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
|
||||
c.JSON(422, resp.CodeMsg(422002, "bind err: neId/imsi/num is empty"))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -476,7 +475,7 @@ func (s *UDMSubController) Export(c *gin.Context) {
|
||||
neId := c.Query("neId")
|
||||
fileType := c.Query("type")
|
||||
if neId == "" || fileType == "" {
|
||||
c.JSON(400, resp.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
|
||||
c.JSON(422, resp.CodeMsg(422002, "bind err: neId or type is empty"))
|
||||
return
|
||||
}
|
||||
if !(fileType == "csv" || fileType == "txt") {
|
||||
@@ -556,7 +555,7 @@ func (s *UDMSubController) Import(c *gin.Context) {
|
||||
}
|
||||
if err := c.ShouldBindBodyWithJSON(&body); err != nil {
|
||||
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||||
c.JSON(422, resp.CodeMsg(40422, errMsgs))
|
||||
c.JSON(422, resp.CodeMsg(422001, errMsgs))
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
561
src/modules/network_data/controller/udm_voip.go
Normal file
561
src/modules/network_data/controller/udm_voip.go
Normal file
@@ -0,0 +1,561 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"be.ems/src/framework/constants"
|
||||
"be.ems/src/framework/i18n"
|
||||
"be.ems/src/framework/reqctx"
|
||||
"be.ems/src/framework/resp"
|
||||
"be.ems/src/framework/telnet"
|
||||
"be.ems/src/framework/utils/file"
|
||||
"be.ems/src/framework/utils/parse"
|
||||
"be.ems/src/modules/network_data/model"
|
||||
neDataService "be.ems/src/modules/network_data/service"
|
||||
neService "be.ems/src/modules/network_element/service"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// 实例化控制层 UDMVOIPController 结构体
|
||||
var NewUDMVOIP = &UDMVOIPController{
|
||||
udmVOIPService: neDataService.NewUDMVOIPUser,
|
||||
neInfoService: neService.NewNeInfo,
|
||||
}
|
||||
|
||||
// UDMVOIP用户
|
||||
//
|
||||
// PATH /udm/voip
|
||||
type UDMVOIPController struct {
|
||||
udmVOIPService *neDataService.UDMVOIPUser // UDMVOIP信息服务
|
||||
neInfoService *neService.NeInfo // 网元信息服务
|
||||
}
|
||||
|
||||
// UDMVOIP用户重载数据
|
||||
//
|
||||
// PUT /resetData/:neId
|
||||
//
|
||||
// @Tags network_data/udm/voip
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param neId path string true "NE ID" default(001)
|
||||
// @Success 200 {object} object "Response Results"
|
||||
// @Security TokenAuth
|
||||
// @Summary UDM VOIP User Data Refresh
|
||||
// @Description UDM VOIP User Data List Refresh Synchronization Latest
|
||||
// @Router /neData/udm/voip/resetData/{neId} [put]
|
||||
func (s *UDMVOIPController) ResetData(c *gin.Context) {
|
||||
neId := c.Param("neId")
|
||||
if neId == "" {
|
||||
c.JSON(422, resp.CodeMsg(422002, "bind err: neId is empty"))
|
||||
return
|
||||
}
|
||||
|
||||
data := s.udmVOIPService.ResetData(neId)
|
||||
c.JSON(200, resp.OkData(data))
|
||||
}
|
||||
|
||||
// UDMVOIP用户列表
|
||||
//
|
||||
// GET /list
|
||||
//
|
||||
// @Tags network_data/udm/voip
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param neId query string true "NE ID" default(001)
|
||||
// @Param username query string false "User Name"
|
||||
// @Param pageNum query number true "pageNum" default(1)
|
||||
// @Param pageSize query number true "pageSize" default(10)
|
||||
// @Success 200 {object} object "Response Results"
|
||||
// @Security TokenAuth
|
||||
// @Summary UDM VOIP User List
|
||||
// @Description UDM VOIP User List
|
||||
// @Router /neData/udm/voip/list [get]
|
||||
func (s *UDMVOIPController) List(c *gin.Context) {
|
||||
query := reqctx.QueryMap(c)
|
||||
total, rows := s.udmVOIPService.FindByPage(query)
|
||||
c.JSON(200, resp.OkData(map[string]any{"total": total, "rows": rows}))
|
||||
}
|
||||
|
||||
// UDMVOIP用户信息
|
||||
//
|
||||
// GET /:neId/:username
|
||||
//
|
||||
// @Tags network_data/udm/voip
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param neId path string true "NE ID" default(001)
|
||||
// @Param value path string true "User Name"
|
||||
// @Success 200 {object} object "Response Results"
|
||||
// @Security TokenAuth
|
||||
// @Summary UDM VOIP User Information
|
||||
// @Description UDM VOIP User Information
|
||||
// @Router /neData/udm/voip/{neId}/{value} [get]
|
||||
func (s *UDMVOIPController) Info(c *gin.Context) {
|
||||
language := reqctx.AcceptLanguage(c)
|
||||
neId := c.Param("neId")
|
||||
username := c.Param("username")
|
||||
if neId == "" || username == "" {
|
||||
c.JSON(422, resp.CodeMsg(422002, "bind err: neId or username is empty"))
|
||||
return
|
||||
}
|
||||
|
||||
// 查询网元获取IP
|
||||
neInfo := s.neInfoService.FindByNeTypeAndNeID("UDM", neId)
|
||||
if neInfo.NeId != neId || neInfo.IP == "" {
|
||||
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
|
||||
return
|
||||
}
|
||||
// 网元主机的Telnet客户端
|
||||
telnetClient, err := s.neInfoService.NeRunTelnetClient("UDM", neId, 1)
|
||||
if err != nil {
|
||||
c.JSON(200, resp.ErrMsg(err.Error()))
|
||||
return
|
||||
}
|
||||
defer telnetClient.Close()
|
||||
|
||||
// 发送MML
|
||||
cmd := fmt.Sprintf("dsp voip:username=%s", username)
|
||||
data, err := telnet.ConvertToMap(telnetClient, cmd)
|
||||
if err != nil {
|
||||
c.JSON(200, resp.ErrMsg(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
if len(data) == 0 {
|
||||
c.JSON(200, resp.ErrMsg("No VOIP Data"))
|
||||
return
|
||||
}
|
||||
|
||||
// 解析返回的数据
|
||||
u := s.udmVOIPService.ParseInfo(neId, data)
|
||||
if u.ID != "" {
|
||||
s.udmVOIPService.Insert(neId, u.UserName)
|
||||
c.JSON(200, resp.OkData(u))
|
||||
return
|
||||
}
|
||||
c.JSON(200, resp.ErrMsg("No VOIP Data"))
|
||||
}
|
||||
|
||||
// UDMVOIP用户新增
|
||||
//
|
||||
// POST /:neId
|
||||
//
|
||||
// @Tags network_data/udm/voip
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param neId path string true "NE ID" default(001)
|
||||
// @Param data body object true "Request Param"
|
||||
// @Success 200 {object} object "Response Results"
|
||||
// @Security TokenAuth
|
||||
// @Summary UDM VOIP User Added
|
||||
// @Description UDM VOIP User Added
|
||||
// @Router /neData/udm/voip/{neId} [post]
|
||||
func (s *UDMVOIPController) Add(c *gin.Context) {
|
||||
language := reqctx.AcceptLanguage(c)
|
||||
neId := c.Param("neId")
|
||||
if neId == "" {
|
||||
c.JSON(422, resp.CodeMsg(422002, "bind err: neId is empty"))
|
||||
return
|
||||
}
|
||||
|
||||
var body model.UDMVOIPUser
|
||||
if err := c.ShouldBindBodyWithJSON(&body); err != nil {
|
||||
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||||
c.JSON(422, resp.CodeMsg(422001, errMsgs))
|
||||
return
|
||||
}
|
||||
if body.UserName == "" {
|
||||
c.JSON(422, resp.CodeMsg(422002, "bind err: username is empty"))
|
||||
return
|
||||
}
|
||||
|
||||
// 查询网元获取IP
|
||||
neInfo := s.neInfoService.FindByNeTypeAndNeID("UDM", neId)
|
||||
if neInfo.NeId != neId || neInfo.IP == "" {
|
||||
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
|
||||
return
|
||||
}
|
||||
// 网元主机的Telnet客户端
|
||||
telnetClient, err := s.neInfoService.NeRunTelnetClient("UDM", neId, 1)
|
||||
if err != nil {
|
||||
c.JSON(200, resp.ErrMsg(err.Error()))
|
||||
return
|
||||
}
|
||||
defer telnetClient.Close()
|
||||
|
||||
// 发送MML
|
||||
cmd := fmt.Sprintf("add voip:username=%s,password=%s", body.UserName, body.Password)
|
||||
data, err := telnet.ConvertToStr(telnetClient, cmd)
|
||||
if err != nil {
|
||||
c.JSON(200, resp.ErrMsg(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
// 命令ok时
|
||||
if strings.Contains(data, "ok") {
|
||||
s.udmVOIPService.Insert(neId, body.UserName)
|
||||
}
|
||||
c.JSON(200, resp.OkData(data))
|
||||
}
|
||||
|
||||
// UDMVOIP用户批量新增
|
||||
//
|
||||
// POST /:neId/:num
|
||||
//
|
||||
// @Tags network_data/udm/voip
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param neId path string true "NE ID" default(001)
|
||||
// @Param value path number true "Number of releases, value includes start username"
|
||||
// @Param data body object true "Request Param"
|
||||
// @Success 200 {object} object "Response Results"
|
||||
// @Security TokenAuth
|
||||
// @Summary UDM VOIP User Batch Add
|
||||
// @Description UDM VOIP User Batch Add
|
||||
// @Router /neData/udm/voip/{neId}/{value} [post]
|
||||
func (s *UDMVOIPController) Adds(c *gin.Context) {
|
||||
language := reqctx.AcceptLanguage(c)
|
||||
neId := c.Param("neId")
|
||||
num := c.Param("num")
|
||||
if neId == "" || num == "" {
|
||||
c.JSON(422, resp.CodeMsg(422002, "bind err: neId or num is empty"))
|
||||
return
|
||||
}
|
||||
|
||||
var body model.UDMVOIPUser
|
||||
if err := c.ShouldBindBodyWithJSON(&body); err != nil {
|
||||
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||||
c.JSON(422, resp.CodeMsg(422001, errMsgs))
|
||||
return
|
||||
}
|
||||
if body.UserName == "" {
|
||||
c.JSON(422, resp.CodeMsg(422002, "bind err: username is empty"))
|
||||
return
|
||||
}
|
||||
|
||||
// 查询网元获取IP
|
||||
neInfo := s.neInfoService.FindByNeTypeAndNeID("UDM", neId)
|
||||
if neInfo.NeId != neId || neInfo.IP == "" {
|
||||
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
|
||||
return
|
||||
}
|
||||
// 网元主机的Telnet客户端
|
||||
telnetClient, err := s.neInfoService.NeRunTelnetClient("UDM", neId, 1)
|
||||
if err != nil {
|
||||
c.JSON(200, resp.ErrMsg(err.Error()))
|
||||
return
|
||||
}
|
||||
defer telnetClient.Close()
|
||||
|
||||
// 发送MML
|
||||
cmd := fmt.Sprintf("baa voip:sub_num=%s,start_username=%s,password=%s", num, body.UserName, body.Password)
|
||||
data, err := telnet.ConvertToStr(telnetClient, cmd)
|
||||
if err != nil {
|
||||
c.JSON(200, resp.ErrMsg(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
// 命令ok时
|
||||
if strings.Contains(data, "ok") {
|
||||
s.udmVOIPService.LoadData(neId, body.UserName, num)
|
||||
}
|
||||
c.JSON(200, resp.OkData(data))
|
||||
}
|
||||
|
||||
// UDMVOIP用户删除
|
||||
//
|
||||
// DELETE /:neId/:username
|
||||
//
|
||||
// @Tags network_data/udm/voip
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param neId path string true "NE ID" default(001)
|
||||
// @Param value path string true "User Name, multiple separated by a , sign"
|
||||
// @Success 200 {object} object "Response Results"
|
||||
// @Security TokenAuth
|
||||
// @Summary UDM VOIP User Deletion
|
||||
// @Description UDM VOIP User Deletion
|
||||
// @Router /neData/udm/voip/{neId}/{value} [delete]
|
||||
func (s *UDMVOIPController) Remove(c *gin.Context) {
|
||||
language := reqctx.AcceptLanguage(c)
|
||||
neId := c.Param("neId")
|
||||
username := c.Param("username")
|
||||
if neId == "" || username == "" {
|
||||
c.JSON(422, resp.CodeMsg(422002, "bind err: neId or username is empty"))
|
||||
return
|
||||
}
|
||||
|
||||
// 处理字符转id数组后去重
|
||||
usernameArr := strings.Split(username, ",")
|
||||
uniqueIDs := parse.RemoveDuplicates(usernameArr)
|
||||
if len(uniqueIDs) <= 0 {
|
||||
c.JSON(200, resp.Err(nil))
|
||||
return
|
||||
}
|
||||
|
||||
// 查询网元获取IP
|
||||
neInfo := s.neInfoService.FindByNeTypeAndNeID("UDM", neId)
|
||||
if neInfo.NeId != neId || neInfo.IP == "" {
|
||||
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
|
||||
return
|
||||
}
|
||||
// 网元主机的Telnet客户端
|
||||
telnetClient, err := s.neInfoService.NeRunTelnetClient("UDM", neId, 1)
|
||||
if err != nil {
|
||||
c.JSON(200, resp.ErrMsg(err.Error()))
|
||||
return
|
||||
}
|
||||
defer telnetClient.Close()
|
||||
|
||||
resultData := map[string]string{}
|
||||
for _, v := range uniqueIDs {
|
||||
// 发送MML
|
||||
cmd := fmt.Sprintf("del voip:username=%s", v)
|
||||
data, err := telnet.ConvertToStr(telnetClient, cmd)
|
||||
if err != nil {
|
||||
resultData[v] = err.Error()
|
||||
continue
|
||||
}
|
||||
// 命令ok时
|
||||
if strings.Contains(data, "ok") {
|
||||
s.udmVOIPService.Delete(v, neId)
|
||||
}
|
||||
resultData[v] = data
|
||||
}
|
||||
|
||||
c.JSON(200, resp.OkData(resultData))
|
||||
}
|
||||
|
||||
// UDMVOIP用户批量删除
|
||||
//
|
||||
// DELETE /:neId/:username/:num
|
||||
//
|
||||
// @Tags network_data/udm/voip
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param neId path string true "NE ID" default(001)
|
||||
// @Param username path string true "User Name"
|
||||
// @Param num path number true "Number of releases, value includes start username"
|
||||
// @Success 200 {object} object "Response Results"
|
||||
// @Security TokenAuth
|
||||
// @Summary UDM VOIP User Batch Deletion
|
||||
// @Description UDM VOIP User Batch Deletion
|
||||
// @Router /neData/udm/voip/{neId}/{username}/{num} [delete]
|
||||
func (s *UDMVOIPController) Removes(c *gin.Context) {
|
||||
language := reqctx.AcceptLanguage(c)
|
||||
neId := c.Param("neId")
|
||||
username := c.Param("username")
|
||||
num := c.Param("num")
|
||||
if neId == "" || username == "" || num == "" {
|
||||
c.JSON(422, resp.CodeMsg(422002, "bind err: neId/username/num is empty"))
|
||||
return
|
||||
}
|
||||
|
||||
// 查询网元获取IP
|
||||
neInfo := s.neInfoService.FindByNeTypeAndNeID("UDM", neId)
|
||||
if neInfo.NeId != neId || neInfo.IP == "" {
|
||||
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
|
||||
return
|
||||
}
|
||||
// 网元主机的Telnet客户端
|
||||
telnetClient, err := s.neInfoService.NeRunTelnetClient("UDM", neId, 1)
|
||||
if err != nil {
|
||||
c.JSON(200, resp.ErrMsg(err.Error()))
|
||||
return
|
||||
}
|
||||
defer telnetClient.Close()
|
||||
|
||||
// 发送MML
|
||||
cmd := fmt.Sprintf("bde voip:start_username=%s,sub_num=%s", username, num)
|
||||
data, err := telnet.ConvertToStr(telnetClient, cmd)
|
||||
if err != nil {
|
||||
c.JSON(200, resp.ErrMsg(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
// 命令ok时
|
||||
if strings.Contains(data, "ok") {
|
||||
s.udmVOIPService.LoadData(neId, username, num)
|
||||
}
|
||||
c.JSON(200, resp.OkData(data))
|
||||
}
|
||||
|
||||
// UDMVOIP用户导出
|
||||
//
|
||||
// GET /export
|
||||
//
|
||||
// @Tags network_data/udm/voip
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param neId query string true "NE ID" default(001)
|
||||
// @Param type query string true "File Type" Enums(csv,txt) default(txt)
|
||||
// @Param username query string false "User Name"
|
||||
// @Param pageNum query number true "pageNum" default(1)
|
||||
// @Param pageSize query number true "pageSize" default(10)
|
||||
// @Success 200 {object} object "Response Results"
|
||||
// @Security TokenAuth
|
||||
// @Summary UDM VOIP User Export
|
||||
// @Description UDM VOIP User Export
|
||||
// @Router /neData/udm/voip/export [get]
|
||||
func (s *UDMVOIPController) Export(c *gin.Context) {
|
||||
language := reqctx.AcceptLanguage(c)
|
||||
// 查询结果,根据查询条件结果,单页最大值限制
|
||||
neId := c.Query("neId")
|
||||
fileType := c.Query("type")
|
||||
if neId == "" {
|
||||
c.JSON(422, resp.CodeMsg(422002, "bind err: neId is empty"))
|
||||
return
|
||||
}
|
||||
if !(fileType == "csv" || fileType == "txt") {
|
||||
c.JSON(200, resp.ErrMsg("file type error, only support csv,txt"))
|
||||
return
|
||||
}
|
||||
|
||||
query := reqctx.QueryMap(c)
|
||||
total, rows := s.udmVOIPService.FindByPage(query)
|
||||
if total == 0 {
|
||||
// 导出数据记录为空
|
||||
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.exportEmpty")))
|
||||
return
|
||||
}
|
||||
|
||||
// rows := s.udmVOIPService.SelectList(model.UDMVOIPUser{NeId: neId})
|
||||
if len(rows) <= 0 {
|
||||
// 导出数据记录为空
|
||||
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.exportEmpty")))
|
||||
return
|
||||
}
|
||||
|
||||
// 文件名
|
||||
fileName := fmt.Sprintf("udm_voip_user_export_%s_%d.%s", neId, time.Now().UnixMilli(), fileType)
|
||||
filePath := filepath.Join(file.ParseUploadFileDir(constants.UPLOAD_EXPORT), fileName)
|
||||
|
||||
if fileType == "csv" {
|
||||
// 转换数据
|
||||
data := [][]string{}
|
||||
data = append(data, []string{"username", "password"})
|
||||
for _, v := range rows {
|
||||
data = append(data, []string{v.UserName, v.Password})
|
||||
}
|
||||
// 输出到文件
|
||||
if err := file.WriterFileCSV(data, filePath); err != nil {
|
||||
c.JSON(200, resp.ErrMsg(err.Error()))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if fileType == "txt" {
|
||||
// 转换数据
|
||||
data := [][]string{}
|
||||
for _, v := range rows {
|
||||
data = append(data, []string{v.UserName, v.Password})
|
||||
}
|
||||
// 输出到文件
|
||||
if err := file.WriterFileTXT(data, ",", filePath); err != nil {
|
||||
c.JSON(200, resp.ErrMsg(err.Error()))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
c.FileAttachment(filePath, fileName)
|
||||
}
|
||||
|
||||
// UDMVOIP用户导入
|
||||
//
|
||||
// POST /import
|
||||
//
|
||||
// @Tags network_data/udm/voip
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param data body object true "Request Param"
|
||||
// @Success 200 {object} object "Response Results"
|
||||
// @Security TokenAuth
|
||||
// @Summary UDM VOIP User Import
|
||||
// @Description UDM VOIP User Import
|
||||
// @Router /neData/udm/voip/import [post]
|
||||
func (s *UDMVOIPController) Import(c *gin.Context) {
|
||||
language := reqctx.AcceptLanguage(c)
|
||||
var body struct {
|
||||
NeId string `json:"neId" binding:"required"` // 网元ID
|
||||
UploadPath string `json:"uploadPath" binding:"required"` // 上传文件路径
|
||||
}
|
||||
if err := c.ShouldBindBodyWithJSON(&body); err != nil {
|
||||
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||||
c.JSON(422, resp.CodeMsg(422001, errMsgs))
|
||||
return
|
||||
}
|
||||
|
||||
// 判断文件名
|
||||
if !(strings.HasSuffix(body.UploadPath, ".csv") || strings.HasSuffix(body.UploadPath, ".txt")) {
|
||||
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "ne.udm.errImportUserAuthFileFormat")))
|
||||
return
|
||||
}
|
||||
|
||||
// 查询网元获取IP
|
||||
neInfo := s.neInfoService.FindByNeTypeAndNeID("UDM", body.NeId)
|
||||
if neInfo.NeId != body.NeId || neInfo.IP == "" {
|
||||
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
|
||||
return
|
||||
}
|
||||
|
||||
// 网元主机的SSH客户端
|
||||
sshClient, err := s.neInfoService.NeRunSSHClient(neInfo.NeType, neInfo.NeId)
|
||||
if err != nil {
|
||||
c.JSON(200, resp.ErrMsg(err.Error()))
|
||||
return
|
||||
}
|
||||
defer sshClient.Close()
|
||||
// 网元主机的SSH客户端进行文件传输
|
||||
sftpClient, err := sshClient.NewClientSFTP()
|
||||
if err != nil {
|
||||
c.JSON(200, resp.ErrMsg(err.Error()))
|
||||
return
|
||||
}
|
||||
defer sftpClient.Close()
|
||||
|
||||
// 本地文件
|
||||
localFilePath := file.ParseUploadFileAbsPath(body.UploadPath)
|
||||
neFilePath := fmt.Sprintf("/tmp/%s", filepath.Base(localFilePath))
|
||||
// 复制到远程
|
||||
if err = sftpClient.CopyFileLocalToRemote(localFilePath, neFilePath); err != nil {
|
||||
c.JSON(200, resp.ErrMsg("error uploading file"))
|
||||
return
|
||||
}
|
||||
|
||||
// 网元主机的Telnet客户端
|
||||
telnetClient, err := s.neInfoService.NeRunTelnetClient(neInfo.NeType, neInfo.NeId, 1)
|
||||
if err != nil {
|
||||
c.JSON(200, resp.ErrMsg(err.Error()))
|
||||
return
|
||||
}
|
||||
defer telnetClient.Close()
|
||||
|
||||
// 结果信息
|
||||
var resultMsg string
|
||||
var resultErr error
|
||||
|
||||
// 发送MML
|
||||
cmd := fmt.Sprintf("import voip:path=%s", neFilePath)
|
||||
resultMsg, resultErr = telnet.ConvertToStr(telnetClient, cmd)
|
||||
if resultErr != nil {
|
||||
c.JSON(200, resp.ErrMsg(resultErr.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
// 命令ok时
|
||||
if strings.Contains(resultMsg, "ok") {
|
||||
if strings.HasSuffix(body.UploadPath, ".csv") {
|
||||
data := file.ReadFileCSV(localFilePath)
|
||||
go s.udmVOIPService.InsertData(neInfo.NeId, "csv", data)
|
||||
}
|
||||
if strings.HasSuffix(body.UploadPath, ".txt") {
|
||||
data := file.ReadFileTXT(",", localFilePath)
|
||||
go s.udmVOIPService.InsertData(neInfo.NeId, "txt", data)
|
||||
}
|
||||
}
|
||||
c.JSON(200, resp.OkMsg(resultMsg))
|
||||
}
|
||||
590
src/modules/network_data/controller/udm_volte_ims.go
Normal file
590
src/modules/network_data/controller/udm_volte_ims.go
Normal file
@@ -0,0 +1,590 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"be.ems/src/framework/constants"
|
||||
"be.ems/src/framework/i18n"
|
||||
"be.ems/src/framework/reqctx"
|
||||
"be.ems/src/framework/resp"
|
||||
"be.ems/src/framework/telnet"
|
||||
"be.ems/src/framework/utils/file"
|
||||
"be.ems/src/framework/utils/parse"
|
||||
"be.ems/src/modules/network_data/model"
|
||||
neDataService "be.ems/src/modules/network_data/service"
|
||||
neService "be.ems/src/modules/network_element/service"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// 实例化控制层 UDMVolteIMSController 结构体
|
||||
var NewUDMVolteIMS = &UDMVolteIMSController{
|
||||
udmVolteIMSService: neDataService.NewUDMVolteIMSUser,
|
||||
neInfoService: neService.NewNeInfo,
|
||||
}
|
||||
|
||||
// UDMVolteIMS用户
|
||||
//
|
||||
// PATH /udm/volte-ims
|
||||
type UDMVolteIMSController struct {
|
||||
udmVolteIMSService *neDataService.UDMVolteIMSUser // UDMVolteIMS信息服务
|
||||
neInfoService *neService.NeInfo // 网元信息服务
|
||||
}
|
||||
|
||||
// UDMVolteIMS用户重载数据
|
||||
//
|
||||
// PUT /resetData/:neId
|
||||
//
|
||||
// @Tags network_data/udm/volte-ims
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param neId path string true "NE ID" default(001)
|
||||
// @Success 200 {object} object "Response Results"
|
||||
// @Security TokenAuth
|
||||
// @Summary UDM VolteIMS User Data Refresh
|
||||
// @Description UDM Authenticated User Data List Refresh Synchronization Latest
|
||||
// @Router /neData/udm/volte-ims/resetData/{neId} [put]
|
||||
func (s *UDMVolteIMSController) ResetData(c *gin.Context) {
|
||||
neId := c.Param("neId")
|
||||
if neId == "" {
|
||||
c.JSON(422, resp.CodeMsg(422002, "bind err: neId is empty"))
|
||||
return
|
||||
}
|
||||
|
||||
data := s.udmVolteIMSService.ResetData(neId)
|
||||
c.JSON(200, resp.OkData(data))
|
||||
}
|
||||
|
||||
// UDMVolteIMS用户列表
|
||||
//
|
||||
// GET /list
|
||||
//
|
||||
// @Tags network_data/udm/volte-ims
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param neId query string true "NE ID" default(001)
|
||||
// @Param imsi query string false "IMSI"
|
||||
// @Param pageNum query number true "pageNum" default(1)
|
||||
// @Param pageSize query number true "pageSize" default(10)
|
||||
// @Success 200 {object} object "Response Results"
|
||||
// @Security TokenAuth
|
||||
// @Summary UDM VolteIMS User List
|
||||
// @Description UDM VolteIMS User List
|
||||
// @Router /neData/udm/volte-ims/list [get]
|
||||
func (s *UDMVolteIMSController) List(c *gin.Context) {
|
||||
query := reqctx.QueryMap(c)
|
||||
total, rows := s.udmVolteIMSService.FindByPage(query)
|
||||
c.JSON(200, resp.OkData(map[string]any{"total": total, "rows": rows}))
|
||||
}
|
||||
|
||||
// UDMVolteIMS用户信息
|
||||
//
|
||||
// GET /:neId/:imsi
|
||||
//
|
||||
// @Tags network_data/udm/volte-ims
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param neId path string true "NE ID" default(001)
|
||||
// @Param value path string true "IMSI"
|
||||
// @Param msisdn query string true "MSISDN"
|
||||
// @Success 200 {object} object "Response Results"
|
||||
// @Security TokenAuth
|
||||
// @Summary UDM VolteIMS User Information
|
||||
// @Description UDM VolteIMS User Information
|
||||
// @Router /neData/udm/volte-ims/{neId}/{value} [get]
|
||||
func (s *UDMVolteIMSController) Info(c *gin.Context) {
|
||||
language := reqctx.AcceptLanguage(c)
|
||||
neId := c.Param("neId")
|
||||
imsi := c.Param("imsi")
|
||||
msisdn := c.Query("msisdn")
|
||||
if neId == "" || imsi == "" {
|
||||
c.JSON(422, resp.CodeMsg(422002, "bind err: neId or imsi is empty"))
|
||||
return
|
||||
}
|
||||
if msisdn == "" {
|
||||
c.JSON(422, resp.CodeMsg(422002, "bind err: msisdn is required"))
|
||||
return
|
||||
}
|
||||
|
||||
// 查询网元获取IP
|
||||
neInfo := s.neInfoService.FindByNeTypeAndNeID("UDM", neId)
|
||||
if neInfo.NeId != neId || neInfo.IP == "" {
|
||||
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
|
||||
return
|
||||
}
|
||||
// 网元主机的Telnet客户端
|
||||
telnetClient, err := s.neInfoService.NeRunTelnetClient("UDM", neId, 1)
|
||||
if err != nil {
|
||||
c.JSON(200, resp.ErrMsg(err.Error()))
|
||||
return
|
||||
}
|
||||
defer telnetClient.Close()
|
||||
|
||||
// 发送MML
|
||||
cmd := fmt.Sprintf("dsp imsuser:imsi=%s,msisdn=%s", imsi, msisdn)
|
||||
data, err := telnet.ConvertToMap(telnetClient, cmd)
|
||||
if err != nil {
|
||||
c.JSON(200, resp.ErrMsg(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
if len(data) == 0 {
|
||||
c.JSON(200, resp.ErrMsg("No Volte IMS Data"))
|
||||
return
|
||||
}
|
||||
|
||||
// 解析返回的数据
|
||||
u := s.udmVolteIMSService.ParseInfo(neId, data)
|
||||
if u.ID != "" {
|
||||
s.udmVolteIMSService.InsertByIMSI(imsi, neId)
|
||||
c.JSON(200, resp.OkData(u))
|
||||
return
|
||||
}
|
||||
c.JSON(200, resp.ErrMsg("No Volte IMS Data"))
|
||||
}
|
||||
|
||||
// UDMVolteIMS用户新增
|
||||
//
|
||||
// POST /:neId
|
||||
//
|
||||
// @Tags network_data/udm/volte-ims
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param neId path string true "NE ID" default(001)
|
||||
// @Param data body object true "Request Param"
|
||||
// @Success 200 {object} object "Response Results"
|
||||
// @Security TokenAuth
|
||||
// @Summary UDM VolteIMS User Added
|
||||
// @Description UDM VolteIMS User Added If VoIP tag=0, then MSISDN and IMSI need to be the same.
|
||||
// @Router /neData/udm/volte-ims/{neId} [post]
|
||||
func (s *UDMVolteIMSController) Add(c *gin.Context) {
|
||||
language := reqctx.AcceptLanguage(c)
|
||||
neId := c.Param("neId")
|
||||
if neId == "" {
|
||||
c.JSON(422, resp.CodeMsg(422002, "bind err: neId is empty"))
|
||||
return
|
||||
}
|
||||
|
||||
var body model.UDMVolteIMSUser
|
||||
if err := c.ShouldBindBodyWithJSON(&body); err != nil {
|
||||
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||||
c.JSON(422, resp.CodeMsg(422001, errMsgs))
|
||||
return
|
||||
}
|
||||
if body.IMSI == "" {
|
||||
c.JSON(422, resp.CodeMsg(422002, "bind err: imsi is empty"))
|
||||
return
|
||||
}
|
||||
|
||||
// 查询网元获取IP
|
||||
neInfo := s.neInfoService.FindByNeTypeAndNeID("UDM", neId)
|
||||
if neInfo.NeId != neId || neInfo.IP == "" {
|
||||
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
|
||||
return
|
||||
}
|
||||
// 网元主机的Telnet客户端
|
||||
telnetClient, err := s.neInfoService.NeRunTelnetClient("UDM", neId, 1)
|
||||
if err != nil {
|
||||
c.JSON(200, resp.ErrMsg(err.Error()))
|
||||
return
|
||||
}
|
||||
defer telnetClient.Close()
|
||||
|
||||
// 检查同IMSI下msisdn是否存在
|
||||
hasMsisdns := s.udmVolteIMSService.Find(model.UDMVolteIMSUser{IMSI: body.IMSI, MSISDN: body.MSISDN, NeId: neId})
|
||||
if len(hasMsisdns) > 0 {
|
||||
c.JSON(200, resp.ErrMsg("IMSI and MSISDN already exist"))
|
||||
return
|
||||
}
|
||||
|
||||
// 发送MML
|
||||
cmd := fmt.Sprintf("add imsuser:imsi=%s,msisdn=%s,volte=%s,vni=%s", body.IMSI, body.MSISDN, body.Tag, body.VNI)
|
||||
data, err := telnet.ConvertToStr(telnetClient, cmd)
|
||||
if err != nil {
|
||||
c.JSON(200, resp.ErrMsg(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
// 命令ok时
|
||||
if strings.Contains(data, "ok") {
|
||||
s.udmVolteIMSService.InsertByIMSI(body.IMSI, neId)
|
||||
}
|
||||
c.JSON(200, resp.OkData(data))
|
||||
}
|
||||
|
||||
// UDMVolteIMS用户批量新增
|
||||
//
|
||||
// POST /:neId/:num
|
||||
//
|
||||
// @Tags network_data/udm/volte-ims
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param neId path string true "NE ID" default(001)
|
||||
// @Param value path number true "Number of releases, value includes start imsi"
|
||||
// @Param data body object true "Request Param"
|
||||
// @Success 200 {object} object "Response Results"
|
||||
// @Security TokenAuth
|
||||
// @Summary UDM VolteIMS User Batch Add
|
||||
// @Description UDM VolteIMS User Batch Add
|
||||
// @Router /neData/udm/volte-ims/{neId}/{value} [post]
|
||||
func (s *UDMVolteIMSController) Adds(c *gin.Context) {
|
||||
language := reqctx.AcceptLanguage(c)
|
||||
neId := c.Param("neId")
|
||||
num := c.Param("num")
|
||||
if neId == "" || num == "" {
|
||||
c.JSON(400, resp.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
|
||||
return
|
||||
}
|
||||
|
||||
var body model.UDMVolteIMSUser
|
||||
if err := c.ShouldBindBodyWithJSON(&body); err != nil {
|
||||
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||||
c.JSON(422, resp.CodeMsg(422001, errMsgs))
|
||||
return
|
||||
}
|
||||
if body.IMSI == "" {
|
||||
c.JSON(422, resp.CodeMsg(422002, "bind err: imsi is empty"))
|
||||
return
|
||||
}
|
||||
|
||||
// 查询网元获取IP
|
||||
neInfo := s.neInfoService.FindByNeTypeAndNeID("UDM", neId)
|
||||
if neInfo.NeId != neId || neInfo.IP == "" {
|
||||
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
|
||||
return
|
||||
}
|
||||
// 网元主机的Telnet客户端
|
||||
telnetClient, err := s.neInfoService.NeRunTelnetClient("UDM", neId, 1)
|
||||
if err != nil {
|
||||
c.JSON(200, resp.ErrMsg(err.Error()))
|
||||
return
|
||||
}
|
||||
defer telnetClient.Close()
|
||||
|
||||
// 发送MML
|
||||
cmd := fmt.Sprintf("baa imsuser:sub_num=%s,start_imsi=%s,start_msisdn=%s,volte=%s,vni=%s", num, body.IMSI, body.MSISDN, body.Tag, body.VNI)
|
||||
data, err := telnet.ConvertToStr(telnetClient, cmd)
|
||||
if err != nil {
|
||||
c.JSON(200, resp.ErrMsg(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
// 命令ok时
|
||||
if strings.Contains(data, "ok") {
|
||||
s.udmVolteIMSService.LoadData(neId, body.IMSI, num)
|
||||
}
|
||||
c.JSON(200, resp.OkData(data))
|
||||
}
|
||||
|
||||
// UDMVolteIMS用户删除
|
||||
//
|
||||
// DELETE /:neId/:imsi
|
||||
//
|
||||
// @Tags network_data/udm/volte-ims
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param neId path string true "NE ID" default(001)
|
||||
// @Param value path string true "IMSI, multiple separated by a , sign"
|
||||
// @Param msisdn query string false "MSISDN"
|
||||
// @Success 200 {object} object "Response Results"
|
||||
// @Security TokenAuth
|
||||
// @Summary UDM Authenticated User Deletion
|
||||
// @Description UDM Authenticated User Deletion
|
||||
// @Router /neData/udm/volte-ims/{neId}/{value} [delete]
|
||||
func (s *UDMVolteIMSController) Remove(c *gin.Context) {
|
||||
language := reqctx.AcceptLanguage(c)
|
||||
neId := c.Param("neId")
|
||||
imsi := c.Param("imsi")
|
||||
msisdn := c.Query("msisdn")
|
||||
if neId == "" || imsi == "" {
|
||||
c.JSON(400, resp.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
|
||||
return
|
||||
}
|
||||
imsiArr := strings.Split(imsi, ",")
|
||||
|
||||
// 查询网元获取IP
|
||||
neInfo := s.neInfoService.FindByNeTypeAndNeID("UDM", neId)
|
||||
if neInfo.NeId != neId || neInfo.IP == "" {
|
||||
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
|
||||
return
|
||||
}
|
||||
// 网元主机的Telnet客户端
|
||||
telnetClient, err := s.neInfoService.NeRunTelnetClient("UDM", neId, 1)
|
||||
if err != nil {
|
||||
c.JSON(200, resp.ErrMsg(err.Error()))
|
||||
return
|
||||
}
|
||||
defer telnetClient.Close()
|
||||
|
||||
// 精确msisdn删除
|
||||
if msisdn != "" {
|
||||
// 发送MML
|
||||
cmd := fmt.Sprintf("del imsuser:imsi=%s,msisdn=%s", imsiArr[0], msisdn)
|
||||
data, err := telnet.ConvertToStr(telnetClient, cmd)
|
||||
if err != nil {
|
||||
c.JSON(200, resp.ErrMsg(err.Error()))
|
||||
return
|
||||
}
|
||||
// 命令ok时
|
||||
if strings.Contains(data, "ok") {
|
||||
s.udmVolteIMSService.Delete(imsi, neId)
|
||||
}
|
||||
c.JSON(200, resp.OkData(data))
|
||||
return
|
||||
} else {
|
||||
// 处理字符转id数组后去重
|
||||
uniqueIDs := parse.RemoveDuplicates(imsiArr)
|
||||
if len(uniqueIDs) <= 0 {
|
||||
c.JSON(200, resp.Err(nil))
|
||||
return
|
||||
}
|
||||
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.udmVolteIMSService.Delete(imsi, neId)
|
||||
}
|
||||
resultData[imsi] = data
|
||||
}
|
||||
c.JSON(200, resp.OkData(resultData))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// UDMVolteIMS用户批量删除
|
||||
//
|
||||
// DELETE /:neId/:imsi/:num
|
||||
//
|
||||
// @Tags network_data/udm/volte-ims
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param neId path string true "NE ID" default(001)
|
||||
// @Param imsi path string true "IMSI"
|
||||
// @Param num path number true "Number of releases, value includes start imsi"
|
||||
// @Success 200 {object} object "Response Results"
|
||||
// @Security TokenAuth
|
||||
// @Summary UDM VolteIMS User Batch Deletion
|
||||
// @Description UDM VolteIMS User Batch Deletion
|
||||
// @Router /neData/udm/volte-ims/{neId}/{imsi}/{num} [delete]
|
||||
func (s *UDMVolteIMSController) Removes(c *gin.Context) {
|
||||
language := reqctx.AcceptLanguage(c)
|
||||
neId := c.Param("neId")
|
||||
imsi := c.Param("imsi")
|
||||
num := c.Param("num")
|
||||
if neId == "" || imsi == "" || num == "" {
|
||||
c.JSON(422, resp.CodeMsg(422002, "bind err: neId/imsi/num is empty"))
|
||||
return
|
||||
}
|
||||
|
||||
// 查询网元获取IP
|
||||
neInfo := s.neInfoService.FindByNeTypeAndNeID("UDM", neId)
|
||||
if neInfo.NeId != neId || neInfo.IP == "" {
|
||||
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
|
||||
return
|
||||
}
|
||||
// 网元主机的Telnet客户端
|
||||
telnetClient, err := s.neInfoService.NeRunTelnetClient("UDM", neId, 1)
|
||||
if err != nil {
|
||||
c.JSON(200, resp.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, resp.ErrMsg(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
// 命令ok时
|
||||
if strings.Contains(data, "ok") {
|
||||
s.udmVolteIMSService.LoadData(neId, imsi, num)
|
||||
}
|
||||
c.JSON(200, resp.OkData(data))
|
||||
}
|
||||
|
||||
// UDMVolteIMS用户导出
|
||||
//
|
||||
// GET /export
|
||||
//
|
||||
// @Tags network_data/udm/volte-ims
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param neId query string true "NE ID" default(001)
|
||||
// @Param type query string true "File Type" Enums(csv,txt) default(txt)
|
||||
// @Param imsi query string false "IMSI"
|
||||
// @Param pageNum query number true "pageNum" default(1)
|
||||
// @Param pageSize query number true "pageSize" default(10)
|
||||
// @Success 200 {object} object "Response Results"
|
||||
// @Security TokenAuth
|
||||
// @Summary UDM Authenticated User Export
|
||||
// @Description UDM Authenticated User Export
|
||||
// @Router /neData/udm/volte-ims/export [get]
|
||||
func (s *UDMVolteIMSController) Export(c *gin.Context) {
|
||||
language := reqctx.AcceptLanguage(c)
|
||||
// 查询结果,根据查询条件结果,单页最大值限制
|
||||
neId := c.Query("neId")
|
||||
fileType := c.Query("type")
|
||||
if neId == "" {
|
||||
c.JSON(422, resp.CodeMsg(422002, "bind err: neId is empty"))
|
||||
return
|
||||
}
|
||||
if !(fileType == "csv" || fileType == "txt") {
|
||||
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "ne.udm.errImportUserSubFileFormat")))
|
||||
return
|
||||
}
|
||||
|
||||
query := reqctx.QueryMap(c)
|
||||
total, rows := s.udmVolteIMSService.FindByPage(query)
|
||||
if total == 0 {
|
||||
// 导出数据记录为空
|
||||
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.exportEmpty")))
|
||||
return
|
||||
}
|
||||
if len(rows) <= 0 {
|
||||
// 导出数据记录为空
|
||||
c.JSON(200, resp.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(constants.UPLOAD_EXPORT), fileName)
|
||||
|
||||
if fileType == "csv" {
|
||||
// 转换数据
|
||||
data := [][]string{}
|
||||
data = append(data, []string{"IMSI", "MSISDN", "TAG", "VNI"})
|
||||
for _, v := range rows {
|
||||
data = append(data, []string{v.IMSI, v.MSISDN, v.Tag, v.VNI})
|
||||
}
|
||||
// 输出到文件
|
||||
if err := file.WriterFileCSV(data, filePath); err != nil {
|
||||
c.JSON(200, resp.ErrMsg(err.Error()))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if fileType == "txt" {
|
||||
// 转换数据
|
||||
data := [][]string{}
|
||||
for _, v := range rows {
|
||||
data = append(data, []string{v.IMSI, v.MSISDN, v.Tag, v.VNI})
|
||||
}
|
||||
// 输出到文件
|
||||
if err := file.WriterFileTXT(data, ",", filePath); err != nil {
|
||||
c.JSON(200, resp.ErrMsg(err.Error()))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
c.FileAttachment(filePath, fileName)
|
||||
}
|
||||
|
||||
// UDMVolteIMS用户导入
|
||||
//
|
||||
// POST /import
|
||||
//
|
||||
// @Tags network_data/udm/volte-ims
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param data body object true "Request Param"
|
||||
// @Success 200 {object} object "Response Results"
|
||||
// @Security TokenAuth
|
||||
// @Summary UDM Authenticated User Import
|
||||
// @Description UDM Authenticated User Import
|
||||
// @Router /neData/udm/volte-ims/import [post]
|
||||
func (s *UDMVolteIMSController) Import(c *gin.Context) {
|
||||
language := reqctx.AcceptLanguage(c)
|
||||
var body struct {
|
||||
NeId string `json:"neId" binding:"required"` // 网元ID
|
||||
UploadPath string `json:"uploadPath" binding:"required"` // 上传文件路径
|
||||
}
|
||||
if err := c.ShouldBindBodyWithJSON(&body); err != nil {
|
||||
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||||
c.JSON(422, resp.CodeMsg(422001, errMsgs))
|
||||
return
|
||||
}
|
||||
|
||||
// 判断文件名
|
||||
if !(strings.HasSuffix(body.UploadPath, ".csv") || strings.HasSuffix(body.UploadPath, ".txt")) {
|
||||
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "ne.udm.errImportUserAuthFileFormat")))
|
||||
return
|
||||
}
|
||||
|
||||
// 查询网元获取IP
|
||||
neInfo := s.neInfoService.FindByNeTypeAndNeID("UDM", body.NeId)
|
||||
if neInfo.NeId != body.NeId || neInfo.IP == "" {
|
||||
c.JSON(200, resp.ErrMsg(i18n.TKey(language, "app.common.noNEInfo")))
|
||||
return
|
||||
}
|
||||
|
||||
// 网元主机的SSH客户端
|
||||
sshClient, err := s.neInfoService.NeRunSSHClient(neInfo.NeType, neInfo.NeId)
|
||||
if err != nil {
|
||||
c.JSON(200, resp.ErrMsg(err.Error()))
|
||||
return
|
||||
}
|
||||
defer sshClient.Close()
|
||||
// 网元主机的SSH客户端进行文件传输
|
||||
sftpClient, err := sshClient.NewClientSFTP()
|
||||
if err != nil {
|
||||
c.JSON(200, resp.ErrMsg(err.Error()))
|
||||
return
|
||||
}
|
||||
defer sftpClient.Close()
|
||||
|
||||
// 本地文件
|
||||
localFilePath := file.ParseUploadFileAbsPath(body.UploadPath)
|
||||
neFilePath := fmt.Sprintf("/tmp/%s", filepath.Base(localFilePath))
|
||||
// 复制到远程
|
||||
if err = sftpClient.CopyFileLocalToRemote(localFilePath, neFilePath); err != nil {
|
||||
c.JSON(200, resp.ErrMsg("error uploading file"))
|
||||
return
|
||||
}
|
||||
|
||||
// 网元主机的Telnet客户端
|
||||
telnetClient, err := s.neInfoService.NeRunTelnetClient(neInfo.NeType, neInfo.NeId, 1)
|
||||
if err != nil {
|
||||
c.JSON(200, resp.ErrMsg(err.Error()))
|
||||
return
|
||||
}
|
||||
defer telnetClient.Close()
|
||||
|
||||
// 结果信息
|
||||
var resultMsg string
|
||||
var resultErr error
|
||||
|
||||
// 发送MML
|
||||
cmd := fmt.Sprintf("import imsuser:path=%s", neFilePath)
|
||||
resultMsg, resultErr = telnet.ConvertToStr(telnetClient, cmd)
|
||||
if resultErr != nil {
|
||||
c.JSON(200, resp.ErrMsg(resultErr.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
// 命令ok时
|
||||
if strings.Contains(resultMsg, "ok") {
|
||||
if strings.HasSuffix(body.UploadPath, ".csv") {
|
||||
data := file.ReadFileCSV(localFilePath)
|
||||
go s.udmVolteIMSService.InsertData(neInfo.NeId, "csv", data)
|
||||
}
|
||||
if strings.HasSuffix(body.UploadPath, ".txt") {
|
||||
data := file.ReadFileTXT(",", localFilePath)
|
||||
go s.udmVolteIMSService.InsertData(neInfo.NeId, "txt", data)
|
||||
}
|
||||
}
|
||||
c.JSON(200, resp.OkMsg(resultMsg))
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"be.ems/src/framework/i18n"
|
||||
"be.ems/src/framework/reqctx"
|
||||
"be.ems/src/framework/resp"
|
||||
@@ -27,7 +29,7 @@ type UPFController struct {
|
||||
// 总流量数 N3上行 N6下行
|
||||
// 单位 比特(bit)
|
||||
//
|
||||
// GET /totalFlow
|
||||
// GET /flow-total
|
||||
//
|
||||
// @Tags network_data/upf
|
||||
// @Accept json
|
||||
@@ -38,15 +40,16 @@ type UPFController struct {
|
||||
// @Security TokenAuth
|
||||
// @Summary Total number of flows N3 upstream N6 downstream
|
||||
// @Description Total number of flows N3 upstream N6 downstream
|
||||
// @Router /neData/upf/totalFlow [get]
|
||||
func (s UPFController) TotalFlow(c *gin.Context) {
|
||||
// @Router /neData/upf/flow-total [get]
|
||||
func (s UPFController) FlowTotal(c *gin.Context) {
|
||||
language := reqctx.AcceptLanguage(c)
|
||||
var querys struct {
|
||||
NeID string `form:"neId" binding:"required"`
|
||||
Day int `form:"day"`
|
||||
}
|
||||
if err := c.ShouldBindQuery(&querys); querys.Day < 0 || err != nil {
|
||||
c.JSON(400, resp.CodeMsg(400, i18n.TKey(language, "app.common.err400")))
|
||||
errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err))
|
||||
c.JSON(422, resp.CodeMsg(422001, errMsgs))
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
11
src/modules/network_data/model/backup.go
Normal file
11
src/modules/network_data/model/backup.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package model
|
||||
|
||||
// BackupDataFTP 备份数据FTP服务参数结构体
|
||||
type BackupDataFTP struct {
|
||||
Password string `json:"password"` // FTP密码
|
||||
Username string `json:"username" binding:"required"` // FTP用户名
|
||||
ToIp string `json:"toIp" binding:"required"` // FTP服务器IP
|
||||
ToPort int64 `json:"toPort" binding:"required"` // FTP服务器端口
|
||||
Dir string `json:"dir" binding:"required"` // FTP服务器目录
|
||||
Enable bool `json:"enable"` // 是否启用
|
||||
}
|
||||
15
src/modules/network_data/model/udm_voip.go
Normal file
15
src/modules/network_data/model/udm_voip.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package model
|
||||
|
||||
// UDMVOIPUser UDMVOIP用户 udm_voip
|
||||
type UDMVOIPUser struct {
|
||||
ID string `json:"id" gorm:"column:id;primaryKey;autoIncrement"` // 主键
|
||||
NeId string `json:"neId" gorm:"column:ne_id"` // UDM网元标识
|
||||
|
||||
UserName string `json:"username" gorm:"column:username"` // 用户名
|
||||
Password string `json:"password" gorm:"column:password"` // 密码
|
||||
}
|
||||
|
||||
// TableName 表名称
|
||||
func (*UDMVOIPUser) TableName() string {
|
||||
return "udm_voip"
|
||||
}
|
||||
17
src/modules/network_data/model/udm_volte_ims.go
Normal file
17
src/modules/network_data/model/udm_volte_ims.go
Normal file
@@ -0,0 +1,17 @@
|
||||
package model
|
||||
|
||||
// UDMVolteIMSUser UDMVolteIMS用户 udm_volte_ims
|
||||
type UDMVolteIMSUser struct {
|
||||
ID string `json:"id" gorm:"column:id;primaryKey;autoIncrement"` // 主键
|
||||
IMSI string `json:"imsi" gorm:"column:imsi"` // SIM卡/USIM卡ID
|
||||
MSISDN string `json:"msisdn" gorm:"column:msisdn"` // 用户电话号码
|
||||
NeId string `json:"neId" gorm:"column:ne_id"` // UDM网元标识
|
||||
|
||||
Tag string `json:"tag" gorm:"column:tag"` // 0=VoIP, 1=VoLTE
|
||||
VNI string `json:"vni" gorm:"column:vni"` // VNI
|
||||
}
|
||||
|
||||
// TableName 表名称
|
||||
func (*UDMVolteIMSUser) TableName() string {
|
||||
return "udm_volte_ims"
|
||||
}
|
||||
@@ -24,11 +24,11 @@ func Setup(router *gin.Engine) {
|
||||
kpiGroup := neDataGroup.Group("/kpi")
|
||||
{
|
||||
kpiGroup.GET("/title",
|
||||
middleware.PreAuthorize(nil),
|
||||
middleware.AuthorizeUser(nil),
|
||||
controller.NewKPI.KPITitle,
|
||||
)
|
||||
kpiGroup.GET("/data",
|
||||
middleware.PreAuthorize(nil),
|
||||
middleware.AuthorizeUser(nil),
|
||||
controller.NewKPI.KPIData,
|
||||
)
|
||||
}
|
||||
@@ -37,33 +37,40 @@ func Setup(router *gin.Engine) {
|
||||
alarmGroup := neDataGroup.Group("/alarm")
|
||||
{
|
||||
alarmGroup.GET("/list",
|
||||
middleware.PreAuthorize(nil),
|
||||
middleware.AuthorizeUser(nil),
|
||||
controller.NewAlarm.List,
|
||||
)
|
||||
alarmGroup.DELETE("/:id",
|
||||
middleware.PreAuthorize(nil),
|
||||
middleware.AuthorizeUser(nil),
|
||||
controller.NewAlarm.Remove,
|
||||
)
|
||||
alarmGroup.PUT("/clear",
|
||||
middleware.PreAuthorize(nil),
|
||||
middleware.AuthorizeUser(nil),
|
||||
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.alarm", collectlogs.BUSINESS_TYPE_UPDATE)),
|
||||
controller.NewAlarm.Clear,
|
||||
)
|
||||
alarmGroup.PUT("/ack",
|
||||
middleware.PreAuthorize(nil),
|
||||
middleware.AuthorizeUser(nil),
|
||||
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.alarm", collectlogs.BUSINESS_TYPE_UPDATE)),
|
||||
controller.NewAlarm.Ack,
|
||||
)
|
||||
alarmGroup.GET("/export",
|
||||
middleware.AuthorizeUser(nil),
|
||||
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.alarm", collectlogs.BUSINESS_TYPE_EXPORT)),
|
||||
controller.NewAlarm.Export,
|
||||
)
|
||||
}
|
||||
|
||||
// 告警日志数据信息
|
||||
alarmLogGroup := neDataGroup.Group("/alarm/log")
|
||||
{
|
||||
alarmLogGroup.GET("/list",
|
||||
middleware.PreAuthorize(nil),
|
||||
middleware.AuthorizeUser(nil),
|
||||
controller.NewAlarmLog.List,
|
||||
)
|
||||
|
||||
alarmLogGroup.GET("/event",
|
||||
middleware.PreAuthorize(nil),
|
||||
middleware.AuthorizeUser(nil),
|
||||
controller.NewAlarmLog.Event,
|
||||
)
|
||||
}
|
||||
@@ -72,7 +79,7 @@ func Setup(router *gin.Engine) {
|
||||
alarmForwardGroup := neDataGroup.Group("/alarm/forward")
|
||||
{
|
||||
alarmForwardGroup.GET("/log/list",
|
||||
middleware.PreAuthorize(nil),
|
||||
middleware.AuthorizeUser(nil),
|
||||
controller.NewAlarmForward.List,
|
||||
)
|
||||
}
|
||||
@@ -81,11 +88,11 @@ func Setup(router *gin.Engine) {
|
||||
nbStateGroup := neDataGroup.Group("/nb-state")
|
||||
{
|
||||
nbStateGroup.GET("/list",
|
||||
middleware.PreAuthorize(nil),
|
||||
middleware.AuthorizeUser(nil),
|
||||
controller.NewNBState.List,
|
||||
)
|
||||
nbStateGroup.POST("/export",
|
||||
middleware.PreAuthorize(nil),
|
||||
middleware.AuthorizeUser(nil),
|
||||
controller.NewNBState.Export,
|
||||
)
|
||||
}
|
||||
@@ -94,25 +101,25 @@ func Setup(router *gin.Engine) {
|
||||
imsGroup := neDataGroup.Group("/ims")
|
||||
{
|
||||
imsGroup.GET("/cdr/list",
|
||||
middleware.PreAuthorize(nil),
|
||||
middleware.AuthorizeUser(nil),
|
||||
controller.NewIMS.CDRList,
|
||||
)
|
||||
imsGroup.DELETE("/cdr/:id",
|
||||
middleware.PreAuthorize(nil),
|
||||
middleware.AuthorizeUser(nil),
|
||||
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.imsCDR", collectlogs.BUSINESS_TYPE_DELETE)),
|
||||
controller.NewIMS.CDRRemove,
|
||||
)
|
||||
imsGroup.POST("/cdr/export",
|
||||
middleware.PreAuthorize(nil),
|
||||
middleware.AuthorizeUser(nil),
|
||||
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.imsCDR", collectlogs.BUSINESS_TYPE_EXPORT)),
|
||||
controller.NewIMS.CDRExport,
|
||||
)
|
||||
imsGroup.GET("/session/num",
|
||||
middleware.PreAuthorize(nil),
|
||||
middleware.AuthorizeUser(nil),
|
||||
controller.NewIMS.UeSessionNum,
|
||||
)
|
||||
imsGroup.GET("/session/list",
|
||||
middleware.PreAuthorize(nil),
|
||||
middleware.AuthorizeUser(nil),
|
||||
controller.NewIMS.UeSessionList,
|
||||
)
|
||||
}
|
||||
@@ -121,16 +128,16 @@ func Setup(router *gin.Engine) {
|
||||
smscGroup := neDataGroup.Group("/smsc")
|
||||
{
|
||||
smscGroup.GET("/cdr/list",
|
||||
middleware.PreAuthorize(nil),
|
||||
middleware.AuthorizeUser(nil),
|
||||
controller.NewSMSC.CDRList,
|
||||
)
|
||||
smscGroup.DELETE("/cdr/:id",
|
||||
middleware.PreAuthorize(nil),
|
||||
middleware.AuthorizeUser(nil),
|
||||
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.smscCDR", collectlogs.BUSINESS_TYPE_DELETE)),
|
||||
controller.NewSMSC.CDRRemove,
|
||||
)
|
||||
smscGroup.POST("/cdr/export",
|
||||
middleware.PreAuthorize(nil),
|
||||
middleware.AuthorizeUser(nil),
|
||||
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.smscCDR", collectlogs.BUSINESS_TYPE_EXPORT)),
|
||||
controller.NewSMSC.CDRExport,
|
||||
)
|
||||
@@ -140,25 +147,25 @@ func Setup(router *gin.Engine) {
|
||||
smfGroup := neDataGroup.Group("/smf")
|
||||
{
|
||||
smfGroup.GET("/cdr/list",
|
||||
middleware.PreAuthorize(nil),
|
||||
middleware.AuthorizeUser(nil),
|
||||
controller.NewSMF.CDRList,
|
||||
)
|
||||
smfGroup.DELETE("/cdr/:id",
|
||||
middleware.PreAuthorize(nil),
|
||||
middleware.AuthorizeUser(nil),
|
||||
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.smfCDR", collectlogs.BUSINESS_TYPE_DELETE)),
|
||||
controller.NewSMF.CDRRemove,
|
||||
)
|
||||
smfGroup.POST("/cdr/export",
|
||||
middleware.PreAuthorize(nil),
|
||||
middleware.AuthorizeUser(nil),
|
||||
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.smfCDR", collectlogs.BUSINESS_TYPE_EXPORT)),
|
||||
controller.NewSMF.CDRExport,
|
||||
)
|
||||
smfGroup.GET("/sub/num",
|
||||
middleware.PreAuthorize(nil),
|
||||
middleware.AuthorizeUser(nil),
|
||||
controller.NewSMF.SubUserNum,
|
||||
)
|
||||
smfGroup.GET("/sub/list",
|
||||
middleware.PreAuthorize(nil),
|
||||
middleware.AuthorizeUser(nil),
|
||||
controller.NewSMF.SubUserList,
|
||||
)
|
||||
}
|
||||
@@ -167,25 +174,25 @@ func Setup(router *gin.Engine) {
|
||||
amfGroup := neDataGroup.Group("/amf")
|
||||
{
|
||||
amfGroup.GET("/ue/list",
|
||||
middleware.PreAuthorize(nil),
|
||||
middleware.AuthorizeUser(nil),
|
||||
controller.NewAMF.UEList,
|
||||
)
|
||||
amfGroup.DELETE("/ue/:id",
|
||||
middleware.PreAuthorize(nil),
|
||||
middleware.AuthorizeUser(nil),
|
||||
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.amfUE", collectlogs.BUSINESS_TYPE_DELETE)),
|
||||
controller.NewAMF.UERemove,
|
||||
)
|
||||
amfGroup.POST("/ue/export",
|
||||
middleware.PreAuthorize(nil),
|
||||
middleware.AuthorizeUser(nil),
|
||||
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.amfUE", collectlogs.BUSINESS_TYPE_EXPORT)),
|
||||
controller.NewAMF.UEExport,
|
||||
)
|
||||
amfGroup.GET("/nb/list",
|
||||
middleware.PreAuthorize(nil),
|
||||
middleware.AuthorizeUser(nil),
|
||||
controller.NewAMF.NbInfoList,
|
||||
)
|
||||
amfGroup.GET("/nb/list-cfg",
|
||||
middleware.PreAuthorize(nil),
|
||||
middleware.AuthorizeUser(nil),
|
||||
controller.NewAMF.NbStateList,
|
||||
)
|
||||
}
|
||||
@@ -193,9 +200,28 @@ func Setup(router *gin.Engine) {
|
||||
// 网元UPF
|
||||
upfGroup := neDataGroup.Group("/upf")
|
||||
{
|
||||
upfGroup.GET("/totalFlow",
|
||||
middleware.PreAuthorize(nil),
|
||||
controller.NewUPF.TotalFlow,
|
||||
upfGroup.GET("/flow-total",
|
||||
middleware.AuthorizeUser(nil),
|
||||
controller.NewUPF.FlowTotal,
|
||||
)
|
||||
}
|
||||
|
||||
// 备份数据
|
||||
backupGroup := neDataGroup.Group("/backup")
|
||||
{
|
||||
backupGroup.GET("/ftp",
|
||||
middleware.AuthorizeUser(nil),
|
||||
controller.NewBackup.FTPInfo,
|
||||
)
|
||||
backupGroup.PUT("/ftp",
|
||||
middleware.AuthorizeUser(nil),
|
||||
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.backup", collectlogs.BUSINESS_TYPE_OTHER)),
|
||||
controller.NewBackup.FTPUpdate,
|
||||
)
|
||||
backupGroup.POST("/ftp",
|
||||
middleware.AuthorizeUser(nil),
|
||||
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.backup", collectlogs.BUSINESS_TYPE_OTHER)),
|
||||
controller.NewBackup.FTPPush,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -204,50 +230,50 @@ func Setup(router *gin.Engine) {
|
||||
{
|
||||
udmAuthGroup.PUT("/resetData/:neId",
|
||||
repeat.RepeatSubmit(5),
|
||||
middleware.PreAuthorize(nil),
|
||||
middleware.AuthorizeUser(nil),
|
||||
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmAuth", collectlogs.BUSINESS_TYPE_CLEAN)),
|
||||
controller.NewUDMAuth.ResetData,
|
||||
)
|
||||
udmAuthGroup.GET("/list",
|
||||
middleware.PreAuthorize(nil),
|
||||
middleware.AuthorizeUser(nil),
|
||||
controller.NewUDMAuth.List,
|
||||
)
|
||||
udmAuthGroup.GET("/:neId/:imsi",
|
||||
middleware.PreAuthorize(nil),
|
||||
middleware.AuthorizeUser(nil),
|
||||
controller.NewUDMAuth.Info,
|
||||
)
|
||||
udmAuthGroup.POST("/:neId",
|
||||
middleware.PreAuthorize(nil),
|
||||
middleware.AuthorizeUser(nil),
|
||||
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmAuth", collectlogs.BUSINESS_TYPE_INSERT)),
|
||||
controller.NewUDMAuth.Add,
|
||||
)
|
||||
udmAuthGroup.POST("/:neId/:num",
|
||||
middleware.PreAuthorize(nil),
|
||||
middleware.AuthorizeUser(nil),
|
||||
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmAuth", collectlogs.BUSINESS_TYPE_INSERT)),
|
||||
controller.NewUDMAuth.Adds,
|
||||
)
|
||||
udmAuthGroup.PUT("/:neId",
|
||||
middleware.PreAuthorize(nil),
|
||||
middleware.AuthorizeUser(nil),
|
||||
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmAuth", collectlogs.BUSINESS_TYPE_UPDATE)),
|
||||
controller.NewUDMAuth.Edit,
|
||||
)
|
||||
udmAuthGroup.DELETE("/:neId/:imsi",
|
||||
middleware.PreAuthorize(nil),
|
||||
middleware.AuthorizeUser(nil),
|
||||
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmAuth", collectlogs.BUSINESS_TYPE_DELETE)),
|
||||
controller.NewUDMAuth.Remove,
|
||||
)
|
||||
udmAuthGroup.DELETE("/:neId/:imsi/:num",
|
||||
middleware.PreAuthorize(nil),
|
||||
middleware.AuthorizeUser(nil),
|
||||
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmAuth", collectlogs.BUSINESS_TYPE_DELETE)),
|
||||
controller.NewUDMAuth.Removes,
|
||||
)
|
||||
udmAuthGroup.GET("/export",
|
||||
middleware.PreAuthorize(nil),
|
||||
middleware.AuthorizeUser(nil),
|
||||
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmAuth", collectlogs.BUSINESS_TYPE_EXPORT)),
|
||||
controller.NewUDMAuth.Export,
|
||||
)
|
||||
udmAuthGroup.POST("/import",
|
||||
middleware.PreAuthorize(nil),
|
||||
middleware.AuthorizeUser(nil),
|
||||
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmAuth", collectlogs.BUSINESS_TYPE_IMPORT)),
|
||||
controller.NewUDMAuth.Import,
|
||||
)
|
||||
@@ -258,78 +284,176 @@ func Setup(router *gin.Engine) {
|
||||
{
|
||||
udmSubGroup.PUT("/resetData/:neId",
|
||||
repeat.RepeatSubmit(5),
|
||||
middleware.PreAuthorize(nil),
|
||||
middleware.AuthorizeUser(nil),
|
||||
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmSub", collectlogs.BUSINESS_TYPE_CLEAN)),
|
||||
controller.NewUDMSub.ResetData,
|
||||
)
|
||||
udmSubGroup.GET("/list",
|
||||
middleware.PreAuthorize(nil),
|
||||
middleware.AuthorizeUser(nil),
|
||||
controller.NewUDMSub.List,
|
||||
)
|
||||
udmSubGroup.GET("/:neId/:imsi",
|
||||
middleware.PreAuthorize(nil),
|
||||
middleware.AuthorizeUser(nil),
|
||||
controller.NewUDMSub.Info,
|
||||
)
|
||||
udmSubGroup.POST("/:neId",
|
||||
middleware.PreAuthorize(nil),
|
||||
middleware.AuthorizeUser(nil),
|
||||
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmSub", collectlogs.BUSINESS_TYPE_INSERT)),
|
||||
controller.NewUDMSub.Add,
|
||||
)
|
||||
udmSubGroup.POST("/:neId/:num",
|
||||
middleware.PreAuthorize(nil),
|
||||
middleware.AuthorizeUser(nil),
|
||||
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmSub", collectlogs.BUSINESS_TYPE_INSERT)),
|
||||
controller.NewUDMSub.Adds,
|
||||
)
|
||||
udmSubGroup.PUT("/:neId",
|
||||
middleware.PreAuthorize(nil),
|
||||
middleware.AuthorizeUser(nil),
|
||||
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmSub", collectlogs.BUSINESS_TYPE_UPDATE)),
|
||||
controller.NewUDMSub.Edit,
|
||||
)
|
||||
udmSubGroup.DELETE("/:neId/:imsi",
|
||||
middleware.PreAuthorize(nil),
|
||||
middleware.AuthorizeUser(nil),
|
||||
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmSub", collectlogs.BUSINESS_TYPE_DELETE)),
|
||||
controller.NewUDMSub.Remove,
|
||||
)
|
||||
udmSubGroup.DELETE("/:neId/:imsi/:num",
|
||||
middleware.PreAuthorize(nil),
|
||||
middleware.AuthorizeUser(nil),
|
||||
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmSub", collectlogs.BUSINESS_TYPE_DELETE)),
|
||||
controller.NewUDMSub.Removes,
|
||||
)
|
||||
udmSubGroup.GET("/export",
|
||||
middleware.PreAuthorize(nil),
|
||||
middleware.AuthorizeUser(nil),
|
||||
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmSub", collectlogs.BUSINESS_TYPE_EXPORT)),
|
||||
controller.NewUDMSub.Export,
|
||||
)
|
||||
udmSubGroup.POST("/import",
|
||||
middleware.PreAuthorize(nil),
|
||||
middleware.AuthorizeUser(nil),
|
||||
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmSub", collectlogs.BUSINESS_TYPE_IMPORT)),
|
||||
controller.NewUDMSub.Import,
|
||||
)
|
||||
}
|
||||
|
||||
// 网元UDM VOIP用户信息
|
||||
udmVOIPGroup := neDataGroup.Group("/udm/voip")
|
||||
{
|
||||
udmVOIPGroup.PUT("/resetData/:neId",
|
||||
repeat.RepeatSubmit(5),
|
||||
middleware.AuthorizeUser(nil),
|
||||
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmVOIP", collectlogs.BUSINESS_TYPE_CLEAN)),
|
||||
controller.NewUDMVOIP.ResetData,
|
||||
)
|
||||
udmVOIPGroup.GET("/list",
|
||||
middleware.AuthorizeUser(nil),
|
||||
controller.NewUDMVOIP.List,
|
||||
)
|
||||
udmVOIPGroup.GET("/:neId/:username",
|
||||
middleware.AuthorizeUser(nil),
|
||||
controller.NewUDMVOIP.Info,
|
||||
)
|
||||
udmVOIPGroup.POST("/:neId",
|
||||
middleware.AuthorizeUser(nil),
|
||||
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmVOIP", collectlogs.BUSINESS_TYPE_INSERT)),
|
||||
controller.NewUDMVOIP.Add,
|
||||
)
|
||||
udmVOIPGroup.POST("/:neId/:num",
|
||||
middleware.AuthorizeUser(nil),
|
||||
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmVOIP", collectlogs.BUSINESS_TYPE_INSERT)),
|
||||
controller.NewUDMVOIP.Adds,
|
||||
)
|
||||
udmVOIPGroup.DELETE("/:neId/:username",
|
||||
middleware.AuthorizeUser(nil),
|
||||
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmVOIP", collectlogs.BUSINESS_TYPE_DELETE)),
|
||||
controller.NewUDMVOIP.Remove,
|
||||
)
|
||||
udmVOIPGroup.DELETE("/:neId/:username/:num",
|
||||
middleware.AuthorizeUser(nil),
|
||||
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmVOIP", collectlogs.BUSINESS_TYPE_DELETE)),
|
||||
controller.NewUDMVOIP.Removes,
|
||||
)
|
||||
udmVOIPGroup.GET("/export",
|
||||
middleware.AuthorizeUser(nil),
|
||||
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmVOIP", collectlogs.BUSINESS_TYPE_EXPORT)),
|
||||
controller.NewUDMVOIP.Export,
|
||||
)
|
||||
udmVOIPGroup.POST("/import",
|
||||
middleware.AuthorizeUser(nil),
|
||||
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmVOIP", collectlogs.BUSINESS_TYPE_IMPORT)),
|
||||
controller.NewUDMVOIP.Import,
|
||||
)
|
||||
}
|
||||
|
||||
// 网元UDM VolteIMS用户信息
|
||||
udmVolteIMSGroup := neDataGroup.Group("/udm/volte-ims")
|
||||
{
|
||||
udmVolteIMSGroup.PUT("/resetData/:neId",
|
||||
repeat.RepeatSubmit(5),
|
||||
middleware.AuthorizeUser(nil),
|
||||
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmVolteIMS", collectlogs.BUSINESS_TYPE_CLEAN)),
|
||||
controller.NewUDMVolteIMS.ResetData,
|
||||
)
|
||||
udmVolteIMSGroup.GET("/list",
|
||||
middleware.AuthorizeUser(nil),
|
||||
controller.NewUDMVolteIMS.List,
|
||||
)
|
||||
udmVolteIMSGroup.GET("/:neId/:imsi",
|
||||
middleware.AuthorizeUser(nil),
|
||||
controller.NewUDMVolteIMS.Info,
|
||||
)
|
||||
udmVolteIMSGroup.POST("/:neId",
|
||||
middleware.AuthorizeUser(nil),
|
||||
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmVolteIMS", collectlogs.BUSINESS_TYPE_INSERT)),
|
||||
controller.NewUDMVolteIMS.Add,
|
||||
)
|
||||
udmVolteIMSGroup.POST("/:neId/:num",
|
||||
middleware.AuthorizeUser(nil),
|
||||
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmVolteIMS", collectlogs.BUSINESS_TYPE_INSERT)),
|
||||
controller.NewUDMVolteIMS.Adds,
|
||||
)
|
||||
udmVolteIMSGroup.DELETE("/:neId/:imsi",
|
||||
middleware.AuthorizeUser(nil),
|
||||
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmVolteIMS", collectlogs.BUSINESS_TYPE_DELETE)),
|
||||
controller.NewUDMVolteIMS.Remove,
|
||||
)
|
||||
udmVolteIMSGroup.DELETE("/:neId/:imsi/:num",
|
||||
middleware.AuthorizeUser(nil),
|
||||
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmVolteIMS", collectlogs.BUSINESS_TYPE_DELETE)),
|
||||
controller.NewUDMVolteIMS.Removes,
|
||||
)
|
||||
udmVolteIMSGroup.GET("/export",
|
||||
middleware.AuthorizeUser(nil),
|
||||
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmVolteIMS", collectlogs.BUSINESS_TYPE_EXPORT)),
|
||||
controller.NewUDMVolteIMS.Export,
|
||||
)
|
||||
udmVolteIMSGroup.POST("/import",
|
||||
middleware.AuthorizeUser(nil),
|
||||
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.udmVolteIMS", collectlogs.BUSINESS_TYPE_IMPORT)),
|
||||
controller.NewUDMVolteIMS.Import,
|
||||
)
|
||||
}
|
||||
|
||||
// 网元MME
|
||||
mmeGroup := neDataGroup.Group("/mme")
|
||||
{
|
||||
mmeGroup.GET("/ue/list",
|
||||
middleware.PreAuthorize(nil),
|
||||
middleware.AuthorizeUser(nil),
|
||||
controller.NewMME.UEList,
|
||||
)
|
||||
mmeGroup.DELETE("/ue/:id",
|
||||
middleware.PreAuthorize(nil),
|
||||
middleware.AuthorizeUser(nil),
|
||||
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.mmeUE", collectlogs.BUSINESS_TYPE_DELETE)),
|
||||
controller.NewMME.UERemove,
|
||||
)
|
||||
mmeGroup.POST("/ue/export",
|
||||
middleware.PreAuthorize(nil),
|
||||
middleware.AuthorizeUser(nil),
|
||||
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.mmeUE", collectlogs.BUSINESS_TYPE_EXPORT)),
|
||||
controller.NewMME.UEExport,
|
||||
)
|
||||
mmeGroup.GET("/nb/list",
|
||||
middleware.PreAuthorize(nil),
|
||||
middleware.AuthorizeUser(nil),
|
||||
controller.NewMME.NbInfoList,
|
||||
)
|
||||
mmeGroup.GET("/nb/list-cfg",
|
||||
middleware.PreAuthorize(nil),
|
||||
middleware.AuthorizeUser(nil),
|
||||
controller.NewMME.NbStateList,
|
||||
)
|
||||
}
|
||||
@@ -338,16 +462,16 @@ func Setup(router *gin.Engine) {
|
||||
sgwcGroup := neDataGroup.Group("/sgwc")
|
||||
{
|
||||
sgwcGroup.GET("/cdr/list",
|
||||
middleware.PreAuthorize(nil),
|
||||
middleware.AuthorizeUser(nil),
|
||||
controller.NewSGWC.CDRList,
|
||||
)
|
||||
sgwcGroup.DELETE("/cdr/:id",
|
||||
middleware.PreAuthorize(nil),
|
||||
middleware.AuthorizeUser(nil),
|
||||
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.sgwcCDR", collectlogs.BUSINESS_TYPE_DELETE)),
|
||||
controller.NewSGWC.CDRRemove,
|
||||
)
|
||||
sgwcGroup.POST("/cdr/export",
|
||||
middleware.PreAuthorize(nil),
|
||||
middleware.AuthorizeUser(nil),
|
||||
collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.sgwcCDR", collectlogs.BUSINESS_TYPE_EXPORT)),
|
||||
controller.NewSGWC.CDRExport,
|
||||
)
|
||||
|
||||
@@ -18,7 +18,7 @@ type UDMAuthUser struct{}
|
||||
// ClearAndInsert 清空ne_id后新增实体
|
||||
func (r *UDMAuthUser) ClearAndInsert(neId string, uArr []model.UDMAuthUser) int64 {
|
||||
// 不指定neID时,用 TRUNCATE 清空表快
|
||||
// _, err := datasource.ExecDB("", "TRUNCATE TABLE u_auth_user", nil)
|
||||
// _, err := datasource.ExecDB("", "TRUNCATE TABLE udm_auth", nil)
|
||||
result := db.DB("").Where("ne_id = ?", neId).Unscoped().Delete(&model.UDMAuthUser{})
|
||||
if result.Error != nil {
|
||||
logger.Errorf("Delete err => %v", result.Error)
|
||||
@@ -39,6 +39,7 @@ func (r *UDMAuthUser) SelectPage(query map[string]string) (int64, []model.UDMAut
|
||||
if v, ok := query["imsis"]; ok && v != "" {
|
||||
arr := strings.Split(v, ",")
|
||||
tx = tx.Where("imsi in ?", arr)
|
||||
// 勾选时,pageSize为勾选的数量
|
||||
query["pageSize"] = fmt.Sprint(len(arr))
|
||||
}
|
||||
|
||||
@@ -126,7 +127,7 @@ func (r *UDMAuthUser) Delete(imsi, neId string) int64 {
|
||||
}
|
||||
|
||||
// DeletePrefixByIMSI 删除前缀匹配的实体
|
||||
func (r *UDMAuthUser) DeletePrefixByIMSI(neId, imsi string) int64 {
|
||||
func (r *UDMAuthUser) DeletePrefixByIMSI(imsi, neId string) int64 {
|
||||
tx := db.DB("").Where("imsi like ? and ne_id = ?", fmt.Sprintf("%s%%", imsi), neId).Delete(&model.UDMAuthUser{})
|
||||
if err := tx.Error; err != nil {
|
||||
logger.Errorf("DeletePrefixByIMSI err => %v", err)
|
||||
|
||||
@@ -18,7 +18,7 @@ type UDMSubUser struct{}
|
||||
// ClearAndInsert 清空ne_id后新增实体
|
||||
func (r *UDMSubUser) ClearAndInsert(neId string, u []model.UDMSubUser) int64 {
|
||||
// 不指定neID时,用 TRUNCATE 清空表快
|
||||
// _, err := datasource.ExecDB("", "TRUNCATE TABLE u_sub_user", nil)
|
||||
// _, err := datasource.ExecDB("", "TRUNCATE TABLE udm_sub", nil)
|
||||
result := db.DB("").Where("ne_id = ?", neId).Unscoped().Delete(&model.UDMSubUser{})
|
||||
if result.Error != nil {
|
||||
logger.Errorf("Delete err => %v", result.Error)
|
||||
@@ -42,6 +42,7 @@ func (r *UDMSubUser) SelectPage(query map[string]string) (int64, []model.UDMSubU
|
||||
if v, ok := query["imsis"]; ok && v != "" {
|
||||
arr := strings.Split(v, ",")
|
||||
tx = tx.Where("imsi in ?", arr)
|
||||
// 勾选时,pageSize为勾选的数量
|
||||
query["pageSize"] = fmt.Sprint(len(arr))
|
||||
}
|
||||
|
||||
|
||||
138
src/modules/network_data/repository/udm_voip.go
Normal file
138
src/modules/network_data/repository/udm_voip.go
Normal file
@@ -0,0 +1,138 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"be.ems/src/framework/database/db"
|
||||
"be.ems/src/framework/logger"
|
||||
"be.ems/src/modules/network_data/model"
|
||||
)
|
||||
|
||||
// 实例化数据层 UDMVOIPUser 结构体
|
||||
var NewUDMVOIPUser = &UDMVOIPUser{}
|
||||
|
||||
// UDMVOIPUser UDMVOIP用户信息表 数据层处理
|
||||
type UDMVOIPUser struct{}
|
||||
|
||||
// ClearAndInsert 清空ne_id后新增实体
|
||||
func (r UDMVOIPUser) ClearAndInsert(neId string, uArr []model.UDMVOIPUser) int64 {
|
||||
// 不指定neID时,用 TRUNCATE 清空表快
|
||||
// _, err := datasource.ExecDB("", "TRUNCATE TABLE udm_voip", nil)
|
||||
result := db.DB("").Where("ne_id = ?", neId).Unscoped().Delete(&model.UDMVOIPUser{})
|
||||
if result.Error != nil {
|
||||
logger.Errorf("Delete err => %v", result.Error)
|
||||
}
|
||||
return r.Inserts(uArr)
|
||||
}
|
||||
|
||||
// SelectPage 根据条件分页查询
|
||||
func (r UDMVOIPUser) SelectPage(query map[string]string) (int64, []model.UDMVOIPUser) {
|
||||
tx := db.DB("").Model(&model.UDMVOIPUser{})
|
||||
// 查询条件拼接
|
||||
if v, ok := query["username"]; ok && v != "" {
|
||||
tx = tx.Where("username like ?", fmt.Sprintf("%%%s%%", v))
|
||||
}
|
||||
if v, ok := query["neId"]; ok && v != "" {
|
||||
tx = tx.Where("ne_id = ?", v)
|
||||
}
|
||||
if v, ok := query["usernames"]; ok && v != "" {
|
||||
arr := strings.Split(v, ",")
|
||||
tx = tx.Where("username in ?", arr)
|
||||
// 勾选时,pageSize为勾选的数量
|
||||
query["pageSize"] = fmt.Sprint(len(arr))
|
||||
}
|
||||
|
||||
var total int64 = 0
|
||||
rows := []model.UDMVOIPUser{}
|
||||
|
||||
// 查询数量 长度为0直接返回
|
||||
if err := tx.Count(&total).Error; err != nil || total <= 0 {
|
||||
return total, rows
|
||||
}
|
||||
|
||||
// 分页
|
||||
pageNum, pageSize := db.PageNumSize(query["pageNum"], query["pageSize"])
|
||||
tx = tx.Offset(int(pageNum * pageSize)).Limit(int(pageSize))
|
||||
|
||||
// 排序
|
||||
if v, ok := query["sortField"]; ok && v != "" {
|
||||
sortSql := v
|
||||
if o, ok := query["sortOrder"]; ok && o != "" {
|
||||
if o == "desc" {
|
||||
sortSql += " desc "
|
||||
} else {
|
||||
sortSql += " asc "
|
||||
}
|
||||
}
|
||||
tx = tx.Order(sortSql)
|
||||
} else {
|
||||
tx = tx.Order("username asc")
|
||||
}
|
||||
|
||||
// 查询数据
|
||||
if err := tx.Find(&rows).Error; err != nil {
|
||||
logger.Errorf("query err => %v", err)
|
||||
}
|
||||
|
||||
return total, rows
|
||||
}
|
||||
|
||||
// SelectList 根据实体查询
|
||||
func (r UDMVOIPUser) SelectList(u model.UDMVOIPUser) []model.UDMVOIPUser {
|
||||
tx := db.DB("").Model(&model.UDMVOIPUser{})
|
||||
// 查询条件拼接
|
||||
if u.UserName != "" {
|
||||
tx = tx.Where("username = ?", u.UserName)
|
||||
}
|
||||
if u.NeId != "" {
|
||||
tx = tx.Where("ne_id = ?", u.NeId)
|
||||
}
|
||||
|
||||
// 查询数据
|
||||
arr := []model.UDMVOIPUser{}
|
||||
if err := tx.Order("username asc").Find(&arr).Error; err != nil {
|
||||
logger.Errorf("query err => %v", err)
|
||||
}
|
||||
return arr
|
||||
}
|
||||
|
||||
// SelectByUserNameAndNeID 通过username和ne_id查询
|
||||
func (r UDMVOIPUser) SelectByUserNameAndNeID(username, neId string) model.UDMVOIPUser {
|
||||
tx := db.DB("").Model(&model.UDMVOIPUser{})
|
||||
item := model.UDMVOIPUser{}
|
||||
// 查询条件拼接
|
||||
tx = tx.Where("username = ? and ne_id = ?", username, neId)
|
||||
// 查询数据
|
||||
if err := tx.Order("username asc").Limit(1).Find(&item).Error; err != nil {
|
||||
logger.Errorf("query err => %v", err)
|
||||
}
|
||||
return item
|
||||
}
|
||||
|
||||
// Insert 批量添加
|
||||
func (r UDMVOIPUser) Inserts(uArr []model.UDMVOIPUser) int64 {
|
||||
tx := db.DB("").CreateInBatches(uArr, 500)
|
||||
if err := tx.Error; err != nil {
|
||||
logger.Errorf("CreateInBatches err => %v", err)
|
||||
}
|
||||
return tx.RowsAffected
|
||||
}
|
||||
|
||||
// Delete 删除实体
|
||||
func (r UDMVOIPUser) Delete(username, neId string) int64 {
|
||||
tx := db.DB("").Where("username = ? and ne_id = ?", username, neId).Delete(&model.UDMVOIPUser{})
|
||||
if err := tx.Error; err != nil {
|
||||
logger.Errorf("Delete err => %v", err)
|
||||
}
|
||||
return tx.RowsAffected
|
||||
}
|
||||
|
||||
// DeletePrefixByUserName 删除前缀匹配的实体
|
||||
func (r UDMVOIPUser) DeletePrefixByUserName(username, neId string) int64 {
|
||||
tx := db.DB("").Where("username like ? and ne_id = ?", fmt.Sprintf("%s%%", username), neId).Delete(&model.UDMVOIPUser{})
|
||||
if err := tx.Error; err != nil {
|
||||
logger.Errorf("DeletePrefixByUserName err => %v", err)
|
||||
}
|
||||
return tx.RowsAffected
|
||||
}
|
||||
150
src/modules/network_data/repository/udm_volte_ims.go
Normal file
150
src/modules/network_data/repository/udm_volte_ims.go
Normal file
@@ -0,0 +1,150 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"be.ems/src/framework/database/db"
|
||||
"be.ems/src/framework/logger"
|
||||
"be.ems/src/modules/network_data/model"
|
||||
)
|
||||
|
||||
// 实例化数据层 UDMVolteIMSUser 结构体
|
||||
var NewUDMVolteIMSUser = &UDMVolteIMSUser{}
|
||||
|
||||
// UDMVolteIMSUser UDMVOIP用户信息表 数据层处理
|
||||
type UDMVolteIMSUser struct{}
|
||||
|
||||
// ClearAndInsert 清空ne_id后新增实体
|
||||
func (r UDMVolteIMSUser) ClearAndInsert(neId string, uArr []model.UDMVolteIMSUser) int64 {
|
||||
// 不指定neID时,用 TRUNCATE 清空表快
|
||||
// _, err := datasource.ExecDB("", "TRUNCATE TABLE udm_volte_ims", nil)
|
||||
result := db.DB("").Where("ne_id = ?", neId).Unscoped().Delete(&model.UDMVolteIMSUser{})
|
||||
if result.Error != nil {
|
||||
logger.Errorf("Delete err => %v", result.Error)
|
||||
}
|
||||
return r.Inserts(uArr)
|
||||
}
|
||||
|
||||
// SelectPage 根据条件分页查询
|
||||
func (r UDMVolteIMSUser) SelectPage(query map[string]string) (int64, []model.UDMVolteIMSUser) {
|
||||
tx := db.DB("").Model(&model.UDMVolteIMSUser{})
|
||||
// 查询条件拼接
|
||||
if v, ok := query["imsi"]; ok && v != "" {
|
||||
tx = tx.Where("imsi like ?", fmt.Sprintf("%%%s%%", v))
|
||||
}
|
||||
if v, ok := query["msisdn"]; ok && v != "" {
|
||||
tx = tx.Where("msisdn like ?", fmt.Sprintf("%%%s%%", v))
|
||||
}
|
||||
if v, ok := query["neId"]; ok && v != "" {
|
||||
tx = tx.Where("ne_id = ?", v)
|
||||
}
|
||||
if v, ok := query["tag"]; ok && v != "" {
|
||||
tx = tx.Where("tag = ?", v)
|
||||
}
|
||||
if v, ok := query["vni"]; ok && v != "" {
|
||||
tx = tx.Where("vni like ?", fmt.Sprintf("%%%s%%", v))
|
||||
}
|
||||
if v, ok := query["imsis"]; ok && v != "" {
|
||||
arr := strings.Split(v, ",")
|
||||
tx = tx.Where("imsi in ?", arr)
|
||||
// 勾选时,pageSize为勾选的数量
|
||||
query["pageSize"] = fmt.Sprint(len(arr))
|
||||
}
|
||||
|
||||
var total int64 = 0
|
||||
rows := []model.UDMVolteIMSUser{}
|
||||
|
||||
// 查询数量 长度为0直接返回
|
||||
if err := tx.Count(&total).Error; err != nil || total <= 0 {
|
||||
return total, rows
|
||||
}
|
||||
|
||||
// 分页
|
||||
pageNum, pageSize := db.PageNumSize(query["pageNum"], query["pageSize"])
|
||||
tx = tx.Offset(int(pageNum * pageSize)).Limit(int(pageSize))
|
||||
|
||||
// 排序
|
||||
if v, ok := query["sortField"]; ok && v != "" {
|
||||
sortSql := v
|
||||
if o, ok := query["sortOrder"]; ok && o != "" {
|
||||
if o == "desc" {
|
||||
sortSql += " desc "
|
||||
} else {
|
||||
sortSql += " asc "
|
||||
}
|
||||
}
|
||||
tx = tx.Order(sortSql)
|
||||
} else {
|
||||
tx = tx.Order("imsi asc")
|
||||
}
|
||||
|
||||
// 查询数据
|
||||
if err := tx.Find(&rows).Error; err != nil {
|
||||
logger.Errorf("query err => %v", err)
|
||||
}
|
||||
|
||||
return total, rows
|
||||
}
|
||||
|
||||
// SelectList 根据实体查询
|
||||
func (r UDMVolteIMSUser) SelectList(u model.UDMVolteIMSUser) []model.UDMVolteIMSUser {
|
||||
tx := db.DB("").Model(&model.UDMVolteIMSUser{})
|
||||
// 查询条件拼接
|
||||
if u.IMSI != "" {
|
||||
tx = tx.Where("imsi = ?", u.IMSI)
|
||||
}
|
||||
if u.NeId != "" {
|
||||
tx = tx.Where("ne_id = ?", u.NeId)
|
||||
}
|
||||
if u.Tag != "" {
|
||||
tx = tx.Where("tag = ?", u.Tag)
|
||||
}
|
||||
|
||||
// 查询数据
|
||||
arr := []model.UDMVolteIMSUser{}
|
||||
if err := tx.Order("imsi asc").Find(&arr).Error; err != nil {
|
||||
logger.Errorf("query err => %v", err)
|
||||
}
|
||||
return arr
|
||||
}
|
||||
|
||||
// SelectByIMSIAndMSISDNAndNeID 通过imsi,msisdn,ne_id查询
|
||||
func (r UDMVolteIMSUser) SelectByIMSIAndMSISDNAndNeID(imsi, msisdn, neId string) model.UDMVolteIMSUser {
|
||||
tx := db.DB("").Model(&model.UDMVolteIMSUser{})
|
||||
item := model.UDMVolteIMSUser{}
|
||||
// 查询条件拼接
|
||||
tx = tx.Where("imsi = ? and msisdn = ? and ne_id = ?", imsi, msisdn, neId)
|
||||
// 查询数据
|
||||
if err := tx.Order("imsi asc").Limit(1).Find(&item).Error; err != nil {
|
||||
logger.Errorf("query err => %v", err)
|
||||
}
|
||||
return item
|
||||
}
|
||||
|
||||
// Insert 批量添加
|
||||
func (r UDMVolteIMSUser) Inserts(uArr []model.UDMVolteIMSUser) int64 {
|
||||
tx := db.DB("").CreateInBatches(uArr, 500)
|
||||
if err := tx.Error; err != nil {
|
||||
logger.Errorf("CreateInBatches err => %v", err)
|
||||
}
|
||||
return tx.RowsAffected
|
||||
}
|
||||
|
||||
// Delete 删除实体
|
||||
func (r UDMVolteIMSUser) Delete(imsi, neId string) int64 {
|
||||
tx := db.DB("").Where("imsi = ? and ne_id = ?", imsi, neId).Delete(&model.UDMVolteIMSUser{})
|
||||
if err := tx.Error; err != nil {
|
||||
logger.Errorf("Delete err => %v", err)
|
||||
}
|
||||
return tx.RowsAffected
|
||||
}
|
||||
|
||||
// DeletePrefixByIMSI 删除前缀匹配的实体
|
||||
func (r UDMVolteIMSUser) DeletePrefixByIMSI(imsi, neId string) int64 {
|
||||
tx := db.DB("").Where("imsi like ? and ne_id = ?", fmt.Sprintf("%s%%", imsi), neId).Delete(&model.UDMVolteIMSUser{})
|
||||
if err := tx.Error; err != nil {
|
||||
logger.Errorf("DeletePrefixByIMSI err => %v", err)
|
||||
}
|
||||
return tx.RowsAffected
|
||||
}
|
||||
@@ -2,11 +2,16 @@ package service
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"be.ems/src/framework/constants"
|
||||
"be.ems/src/framework/i18n"
|
||||
"be.ems/src/framework/utils/date"
|
||||
"be.ems/src/framework/utils/file"
|
||||
"be.ems/src/modules/network_data/model"
|
||||
"be.ems/src/modules/network_data/repository"
|
||||
sysService "be.ems/src/modules/system/service"
|
||||
)
|
||||
|
||||
// 实例化数据层 Alarm 结构体
|
||||
@@ -114,3 +119,83 @@ func (r Alarm) AlarmAckByIds(ids []int64, ackUser string, ackState bool) (int64,
|
||||
// 清除失败!
|
||||
return 0, fmt.Errorf("ack fail")
|
||||
}
|
||||
|
||||
// ExportXlsx 导出数据到 xlsx 文件
|
||||
func (r Alarm) ExportXlsx(rows []model.Alarm, fileName, language, alarmStatus string) (string, error) {
|
||||
// 第一行表头标题
|
||||
headerCells := map[string]string{
|
||||
"A1": i18n.TKey(language, "alarm.export.alarmType"),
|
||||
"B1": i18n.TKey(language, "alarm.export.origSeverity"),
|
||||
"C1": i18n.TKey(language, "alarm.export.alarmTitle"),
|
||||
"D1": i18n.TKey(language, "alarm.export.eventTime"),
|
||||
"E1": i18n.TKey(language, "alarm.export.alarmId"),
|
||||
"F1": i18n.TKey(language, "alarm.export.alarmCode"),
|
||||
"G1": i18n.TKey(language, "ne.common.neType"),
|
||||
"H1": i18n.TKey(language, "ne.common.neName"),
|
||||
"I1": i18n.TKey(language, "ne.common.neId"),
|
||||
}
|
||||
if alarmStatus == "0" {
|
||||
headerCells["J1"] = i18n.TKey(language, "alarm.export.clearUser")
|
||||
headerCells["K1"] = i18n.TKey(language, "alarm.export.clearTime")
|
||||
headerCells["L1"] = i18n.TKey(language, "alarm.export.clearType")
|
||||
}
|
||||
// 读取字典数据 告警原始严重程度
|
||||
dictActiveAlarmType := sysService.NewSysDictData.FindByType("active_alarm_type")
|
||||
// 读取字典数据 告警类型
|
||||
dictActiveClearType := sysService.NewSysDictData.FindByType("active_clear_type")
|
||||
// 读取字典数据 告警确认类型
|
||||
dictActiveAlarmSeverity := sysService.NewSysDictData.FindByType("active_alarm_severity")
|
||||
// 从第二行开始的数据
|
||||
dataCells := make([]map[string]any, 0)
|
||||
for i, row := range rows {
|
||||
idx := strconv.Itoa(i + 2)
|
||||
|
||||
// 原始严重程度
|
||||
origSeverity := "-"
|
||||
for _, v := range dictActiveAlarmSeverity {
|
||||
if row.OrigSeverity == v.DataValue {
|
||||
origSeverity = i18n.TKey(language, v.DataLabel)
|
||||
break
|
||||
}
|
||||
}
|
||||
// 活动告警类型
|
||||
alarmType := "-"
|
||||
for _, v := range dictActiveAlarmType {
|
||||
if row.AlarmType == v.DataValue {
|
||||
alarmType = i18n.TKey(language, v.DataLabel)
|
||||
break
|
||||
}
|
||||
}
|
||||
// 告警清除类型
|
||||
clearType := "-"
|
||||
for _, v := range dictActiveClearType {
|
||||
if fmt.Sprint(row.ClearType) == v.DataValue {
|
||||
clearType = i18n.TKey(language, v.DataLabel)
|
||||
break
|
||||
}
|
||||
}
|
||||
eventTimeStr := date.ParseDateToStr(row.EventTime, date.YYYY_MM_DDTHH_MM_SSZ)
|
||||
|
||||
cells := map[string]any{
|
||||
"A" + idx: alarmType,
|
||||
"B" + idx: origSeverity,
|
||||
"C" + idx: row.AlarmTitle,
|
||||
"D" + idx: eventTimeStr,
|
||||
"E" + idx: row.AlarmId,
|
||||
"F" + idx: row.AlarmCode,
|
||||
"G" + idx: row.NeType,
|
||||
"H" + idx: row.NeName,
|
||||
"I" + idx: row.NeId,
|
||||
}
|
||||
if alarmStatus == "0" {
|
||||
clearTimeStr := date.ParseDateToStr(row.ClearTime, date.YYYY_MM_DDTHH_MM_SSZ)
|
||||
cells["J"+idx] = row.ClearUser
|
||||
cells["K"+idx] = clearType
|
||||
cells["L"+idx] = clearTimeStr
|
||||
}
|
||||
dataCells = append(dataCells, cells)
|
||||
}
|
||||
|
||||
// 导出数据表格
|
||||
return file.WriteSheet(headerCells, dataCells, fileName, "")
|
||||
}
|
||||
|
||||
86
src/modules/network_data/service/backup.go
Normal file
86
src/modules/network_data/service/backup.go
Normal file
@@ -0,0 +1,86 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"be.ems/src/framework/ssh"
|
||||
"be.ems/src/modules/network_data/model"
|
||||
neService "be.ems/src/modules/network_element/service"
|
||||
systemService "be.ems/src/modules/system/service"
|
||||
)
|
||||
|
||||
// 实例化数据层 Backup 结构体
|
||||
var NewBackup = &Backup{
|
||||
BACKUP_DIR: "/usr/local/omc/backup",
|
||||
neInfoService: neService.NewNeInfo,
|
||||
sysConfigService: systemService.NewSysConfig,
|
||||
}
|
||||
|
||||
// Backup 备份相关 服务层处理
|
||||
type Backup struct {
|
||||
BACKUP_DIR string // 备份目录
|
||||
neInfoService *neService.NeInfo // 网元信息服务
|
||||
sysConfigService *systemService.SysConfig // 参数配置服务
|
||||
}
|
||||
|
||||
// FTPConfigUpdate 更新FTP配置信息
|
||||
func (r Backup) FTPConfigUpdate(value, updateBy string) int64 {
|
||||
cfg := r.sysConfigService.FindByKey("neData.backupDataFTP")
|
||||
if cfg.ConfigId == 0 {
|
||||
return 0
|
||||
}
|
||||
cfg.ConfigValue = value
|
||||
cfg.UpdateBy = updateBy
|
||||
return r.sysConfigService.UpdateEncryptValue(cfg)
|
||||
}
|
||||
|
||||
// FTPConfigInfo 获取FTP配置信息
|
||||
func (r Backup) FTPConfigInfo() model.BackupDataFTP {
|
||||
info := model.BackupDataFTP{}
|
||||
// 获取配置
|
||||
cfg := r.sysConfigService.FindByKeyDecryptValue("neData.backupDataFTP")
|
||||
if cfg.ConfigId > 0 && cfg.ConfigValue != "" {
|
||||
if err := json.Unmarshal([]byte(cfg.ConfigValue), &info); err != nil {
|
||||
return info
|
||||
}
|
||||
}
|
||||
return info
|
||||
}
|
||||
|
||||
// FTPPushFile 推送文件到FTP
|
||||
func (r Backup) FTPPushFile(localFilePath, tag string) error {
|
||||
cfgData := r.FTPConfigInfo()
|
||||
if !cfgData.Enable {
|
||||
return fmt.Errorf("setting remote backup ftp is disabled")
|
||||
}
|
||||
|
||||
connSSH := ssh.ConnSSH{
|
||||
User: cfgData.Username,
|
||||
Password: cfgData.Password,
|
||||
Addr: cfgData.ToIp,
|
||||
Port: cfgData.ToPort,
|
||||
AuthMode: "0",
|
||||
}
|
||||
sshClient, err := connSSH.NewClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer sshClient.Close()
|
||||
// 网元主机的SSH客户端进行文件传输
|
||||
sftpClient, err := sshClient.NewClientSFTP()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer sftpClient.Close()
|
||||
|
||||
remotePath := strings.Replace(localFilePath, r.BACKUP_DIR, tag, 1)
|
||||
remotePath = filepath.Join(cfgData.Dir, remotePath)
|
||||
// 复制到远程
|
||||
if err = sftpClient.CopyFileLocalToRemote(localFilePath, remotePath); err != nil {
|
||||
return fmt.Errorf("error uploading file")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -149,7 +149,7 @@ func (r *UDMAuthUser) InsertData(neId, dataType string, data any) int64 {
|
||||
var num int64 = 0
|
||||
for prefix := range prefixes {
|
||||
// 直接删除前缀的记录
|
||||
r.udmAuthRepository.DeletePrefixByIMSI(neId, prefix)
|
||||
r.udmAuthRepository.DeletePrefixByIMSI(prefix, neId)
|
||||
// keys ausf:4600001000004*
|
||||
arr := r.dataByRedis(prefix+"*", neId)
|
||||
if len(arr) > 0 {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user