package service import ( "bufio" "errors" "fmt" "github.com/spf13/cast" "github.com/tealeg/xlsx" "gitlab.wodcloud.com/smart-operation/so-operation-api/src/bean/entity" "gitlab.wodcloud.com/smart-operation/so-operation-api/src/bean/vo/request" "gitlab.wodcloud.com/smart-operation/so-operation-api/src/bean/vo/response" "gitlab.wodcloud.com/smart-operation/so-operation-api/src/common/client" "gitlab.wodcloud.com/smart-operation/so-operation-api/src/common/conf" "gitlab.wodcloud.com/smart-operation/so-operation-api/src/common/tools" "gitlab.wodcloud.com/smart-operation/so-operation-api/src/pkg/beagle/constant" "gitlab.wodcloud.com/smart-operation/so-operation-api/src/pkg/beagle/jsontime" "gitlab.wodcloud.com/smart-operation/so-operation-api/src/pkg/beagle/resp" "gitlab.wodcloud.com/smart-operation/so-operation-api/src/util" "os" "sort" "strconv" "strings" "time" "go.uber.org/zap" ) type LogManagement struct { User entity.SystemUserInfo } func (s *LogManagement) GetSysLogDir(search string) ([]string, error) { file, err := os.Open(conf.Options.LogDirPrefix) if err != nil { zap.L().Error("open file err:", zap.Error(err)) return nil, resp.ReadFileError.WithError(err) } names, err := file.Readdirnames(0) if err != nil { zap.L().Error("read dirnames err:", zap.Error(err)) return nil, resp.ReadFileError.WithError(err) } if search != "" { var filterdNames []string for i := range names { if strings.Index(names[i], search) >= 0 { filterdNames = append(filterdNames, names[i]) } } sort.Slice(filterdNames, func(i, j int) bool { st := strings.Index(filterdNames[i], "-") ed := strings.Index(filterdNames[i], ".") di, _ := time.Parse("2006-01-02", filterdNames[i][st+1:ed]) dj, _ := time.Parse("2006-01-02", filterdNames[j][st+1:ed]) return di.After(dj) }) return filterdNames, nil } sort.Slice(names, func(i, j int) bool { st := strings.Index(names[i], "-") ed := strings.Index(names[i], ".") di, _ := time.Parse("2006-01-02", names[i][st+1:ed]) dj, _ := time.Parse("2006-01-02", names[j][st+1:ed]) return di.After(dj) }) return names, nil } func (s *LogManagement) GetSysLog(logLevel, search, logName string) ([]string, error) { log, err := os.Open(conf.Options.LogDirPrefix + "/" + logName) if err != nil { zap.L().Error("open file err", zap.Error(err)) return nil, resp.ReadFileError.WithError(err) } var logArr []string reader := bufio.NewReader(log) for { rawLine, _, _ := reader.ReadLine() if len(rawLine) == 0 { break } flag1, flag2 := true, true line := string(rawLine) if search != "" { if strings.Index(line, search) < 0 { flag1 = false } } if logLevel != "" { if strings.Index(line, fmt.Sprintf(`"level":"%s"`, strings.ToUpper(logLevel))) < 0 { flag2 = false } } if flag1 && flag2 { logArr = append(logArr, line) } } return logArr, nil } // 用户行为审计列表 func (s *LogManagement) LogUserBehaviorList(params *request.LogUserBehaviorListReq) (list []response.SystemUserBehaviorList, total int64, err error) { db, err := client.GetDbClient() if err != nil { err = resp.DbConnectError.ErrorDetail(err) return nil, 0, err } modelObj := db.Table("system_user_behavior").Alias("sub") modelObj.Join("INNER", []string{"system_user", "su"}, "sub.user_id = su.id") modelObj.Join("INNER", []string{"system_organization", "so"}, "so.organization_id = so.organization_id") modelObj.Select("sub.*, su.system_account, su.phone, so.name as org_name") // 条件查询 if params.Search != "" { keyword := util.SpecialEscape(params.Search) modelObj.Where("system_account like ? or system_module like ? or operate_addr like ?", "%"+keyword+"%", "%"+keyword+"%", "%"+keyword+"%") } // 上次访问时间 if params.StartAt != "" && params.EndAt != "" { applyEndTime, timeErr := time.Parse(jsontime.LocalDateFormat, params.EndAt) if timeErr != nil { conf.Logger.Error("时间转换错误", zap.Error(timeErr)) return nil, 0, resp.DbSelectError.ErrorDetail(timeErr) } EndAt := applyEndTime.AddDate(0, 0, 1).Format(jsontime.LocalDateFormat) modelObj.Where("last_access_time >= ? and last_access_time < ?", params.StartAt, EndAt) } // 操作类型 if params.OperateType != "" { modelObj.Where("operate_type = ?", params.OperateType) } // 请求方式 if params.ReqMethod != 0 { modelObj.Where("req_method = ?", params.ReqMethod) } // 操作状态 if params.OperateStatus != 0 { modelObj.Where("operate_status = ?", params.OperateStatus) } total, err = modelObj.OrderBy("created_time desc").Limit(params.GetPageSize(), params.GetOffset()).FindAndCount(&list) if err != nil { conf.Logger.Error("查询用户行为审计列表失败", zap.Error(err)) err = resp.DbSelectError.WithError(errors.New("查询用户行为审计列表失败")) return nil, 0, err } return list, total, nil } // 用户行为审计导出 func (s *LogManagement) LogUserBehaviorListExport(params *request.LogUserBehaviorListReq) (xlFile *xlsx.File, fileName string, err error) { xlFile = xlsx.NewFile() sheet, err := xlFile.AddSheet("sheet") if err != nil { return nil, "", resp.AddSheetError.ErrorDetail(err) } titleRow := sheet.AddRow() tmp := []string{ "序号", "账号", "手机号", "所属组织", "系统模块", "操作类型", "请求方式", "操作状态", "操作地址", "操作地点", "请求地址", "请求参数", "操作方法", "返回参数", "操作时间", } xlsRow2 := tools.NewRow(titleRow, tmp) err = xlsRow2.SetRowTitle() if err != nil { return } var ( list []response.SystemUserBehaviorList total int64 ) list, total, err = s.LogUserBehaviorList(params) if err != nil { return nil, "", resp.DbSelectError.ErrorDetail(err) } if total == 0 { return nil, "", resp.DbSelectError.ErrorDetail(errors.New("没有可导出的数据")) } fileName = "用户行为审计" + ".xlsx" id := 0 for _, detail := range list { id += 1 currentRow := sheet.AddRow() var tmp = []string{ strconv.Itoa(id), detail.SystemAccount, detail.Phone, detail.OrgName, detail.SystemModule, detail.OperateType, constant.HttpMethodStrMap[detail.ReqMethod], constant.OperateStatusStrMap[detail.OperateStatus], detail.OperateIp, detail.OperateAddr, detail.ReqUrl, detail.ReqParam, constant.HttpMethodStrMap[detail.ReqMethod], detail.ResFields, cast.ToString(detail.CreatedTime), } newRow := tools.NewRow(currentRow, tmp) err := newRow.GenerateRow() if err != nil { return nil, "", resp.AddSheetError.ErrorDetail(err) } } return } // 用户行为审计详情 func (s *LogManagement) LogUserBehaviorDetail(id string) (data *response.LogUserBehaviorDetailRep, err error) { db, err := client.GetDbClient() if err != nil { err = resp.DbConnectError.ErrorDetail(err) return nil, err } data = new(response.LogUserBehaviorDetailRep) modelObj := db.Table("system_user_behavior").Alias("sub") modelObj.Join("INNER", []string{"system_user", "su"}, "sub.user_id = su.id") modelObj.Join("INNER", []string{"system_organization", "so"}, "so.organization_id = su.organization_id") modelObj.Select("sub.*, su.system_account, su.phone, so.name as org_name") _, err = modelObj.Where("sub.id = ?", id).And("sub.is_deleted = 0").Get(data) if err != nil { conf.Logger.Error("获取用户行为审计详情失败", zap.Error(err)) return nil, resp.DbSelectError.ErrorDetail(err) } data.OperateStatusStr = constant.OperateStatusStrMap[data.OperateStatus] data.ReqMethodStr = constant.HttpMethodStrMap[data.ReqMethod] //data.UserType = constant.UserTypeStrMap[data.IsAdmin] return data, nil } func (s *LogManagement) LogUserBehaviorDelete(ids []string) (err error) { db, err := client.GetDbClient() if err != nil { return resp.DbConnectError.ErrorDetail(err) } _, err = db.Table("system_user_behavior").In("id", ids).Update(&map[string]interface{}{"is_deleted": 1}) if err != nil { return resp.DbDeleteError.ErrorDetail(err) } return nil } // LogUserAccountAuditList 行为日志列表 func (s *LogManagement) LogUserAccountAuditList(params *request.LogManagementListReq) ([]response.LogManagementRep, int64, error) { var logManagementRep []response.LogManagementRep db, err := client.GetDbClient() if err != nil { err = resp.DbConnectError.ErrorDetail(err) return nil, 0, err } modelObj := db.Table("system_user as u") modelObj.Join("left", "system_organization as org", "u.organization_id = org.organization_id"). Select(`u.id, u.system_account, u.phone, org.name, u.organization_id, u.last_access_time, case u.pwd_level when 1 then '弱' when 2 then '中' when 3 then '强' end as pwd_level, u.pwd_updated_time, date_part('day', now()-u.pwd_updated_time)as pwd_is_used , u.created_time `) // 条件查询 modelObj.Where("u.is_deleted = 0") if params.Search != "" { keyword := util.SpecialEscape(params.Search) modelObj.Where("u.system_account like ? or u.phone like ? or org.NAME like ?", "%"+keyword+"%", "%"+keyword+"%", "%"+keyword+"%") } // 上次访问时间 if params.StartAt != "" && params.EndAt != "" { applyEndTime, timeErr := time.Parse(jsontime.LocalDateFormat, params.EndAt) if timeErr != nil { conf.Logger.Error("时间转换错误", zap.Error(timeErr)) return nil, 0, resp.DbSelectError.ErrorDetail(timeErr) } EndAt := applyEndTime.AddDate(0, 0, 1).Format(jsontime.LocalDateFormat) modelObj.Where("u.last_access_time >= ? and u.last_access_time < ?", params.StartAt, EndAt) } // 活跃度 1: 低 2:中 3: 高 if params.Active != 0 { switch params.Active { case 1: modelObj.Where("u.last_access_time <= now()-interval '1 month'") case 2: modelObj.Where("u.last_access_time < now()-interval '1 week'").And("u.last_access_time > now()-interval '1 month'") case 3: modelObj.Where("u.last_access_time >= now()-interval '1 week'") } } // 密码强度 if params.PwdLevel != 0 { modelObj.Where("u.pwd_level = ? ", params.PwdLevel) } count, err := modelObj.OrderBy("u.last_access_time desc").Limit(params.GetPageSize(), params.GetOffset()).FindAndCount(&logManagementRep) if err != nil { conf.Logger.Error("查询用户账户审计列表失败", zap.Error(err)) err = resp.DbSelectError.ErrorDetail(errors.New("查询用户账户审计列表失败")) return nil, 0, err } for k := range logManagementRep { active := getActivity(time.Time(logManagementRep[k].LastAccessTimes)) logManagementRep[k].Active = active logManagementRep[k].LastAccessTime = logManagementRep[k].LastAccessTimes } return logManagementRep, count, nil } func getActivity(date time.Time) string { // dates := cast.ToTime(date) var ( lastAccess = date.Unix() pastWeek = time.Now().AddDate(0, 0, -7).Unix() pastMonth = time.Now().AddDate(0, -1, 0).Unix() ) if lastAccess >= pastWeek { return "高" } if lastAccess < pastWeek && lastAccess > pastMonth { return "中" } if lastAccess <= pastMonth { return "低" } return "不活跃" } // LogUserAccountAuditExport 行为日志导出 func (s *LogManagement) LogUserAccountAuditExport(params *request.LogManagementListReq) (xlFile *xlsx.File, fileName string, err error) { xlFile = xlsx.NewFile() sheet, err := xlFile.AddSheet("sheet") if err != nil { conf.Logger.Error("xlFile.AddSheet err", zap.Error(err)) return } titleRow := sheet.AddRow() tmp := []string{ "序号", "账号", "手机号", "所属组织", "上次访问时间", "活跃度", "密码强度", "密码使用时长/天", "创建时间", } xlsRow2 := tools.NewRow(titleRow, tmp) err = xlsRow2.SetRowTitle() if err != nil { return } //params.Page = 0 //params.PageSize = 20000 list, total, err := s.LogUserAccountAuditList(params) if total == 0 { err = errors.New("没有可导出的数据") return } else { fileName = "用户账号审计" + ".xlsx" } id := 0 for _, detail := range list { id += 1 currentRow := sheet.AddRow() var tmp = []string{ strconv.Itoa(id), detail.SystemAccount, detail.Phone, detail.Name, detail.LastAccessTime.String(), detail.Active, detail.PwdLevel, strconv.Itoa(detail.PwdIsUsed), detail.CreatedTime.String(), } newRow := tools.NewRow(currentRow, tmp) err := newRow.GenerateRow() if err != nil { return nil, "", err } } return }