waflog.go 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. package admin
  2. import (
  3. "context"
  4. v1 "github.com/go-nunu/nunu-layout-advanced/api/v1"
  5. adminApi "github.com/go-nunu/nunu-layout-advanced/api/v1/admin"
  6. "github.com/go-nunu/nunu-layout-advanced/internal/model"
  7. "github.com/go-nunu/nunu-layout-advanced/internal/repository"
  8. "gorm.io/gorm"
  9. "math"
  10. "strings"
  11. )
  12. type WafLogRepository interface {
  13. GetWafLog(ctx context.Context, id int64) (*model.WafLog, error)
  14. GetWafLogList(ctx context.Context, req adminApi.SearchWafLogParams) (*v1.PaginatedResponse[model.WafLog], error)
  15. AddWafLog(ctx context.Context, log *model.WafLog) error
  16. BatchAddWafLog(ctx context.Context, logs []*model.WafLog) error
  17. ExportWafLog(ctx context.Context, req adminApi.ExportWafLog) ([]model.WafLogWithGatewayIP, error)
  18. ExportWafLogWithPagination(ctx context.Context, req adminApi.ExportWafLog, page, pageSize int) ([]model.WafLogWithGatewayIP, error)
  19. GetWafLogExportCount(ctx context.Context, req adminApi.ExportWafLog) (int, error)
  20. }
  21. func NewWafLogRepository(
  22. repository *repository.Repository,
  23. ) WafLogRepository {
  24. return &wafLogRepository{
  25. Repository: repository,
  26. }
  27. }
  28. type wafLogRepository struct {
  29. *repository.Repository
  30. }
  31. // buildExportQuery 是一个辅助函数,用于构建导出日志的公共查询条件
  32. func (r *wafLogRepository) buildExportQuery(ctx context.Context, req adminApi.ExportWafLog) *gorm.DB {
  33. // 使用 Table("waf_log as wl") 是为了给主表起一个别名,方便子查询中引用
  34. query := r.DBWithName(ctx, "admin").Model(&model.WafLog{}).Table("waf_log as wl")
  35. if req.RequestIp != "" {
  36. query = query.Where("wl.request_ip = ?", strings.TrimSpace(req.RequestIp))
  37. }
  38. if req.Uid != 0 {
  39. query = query.Where("wl.uid = ?", req.Uid)
  40. }
  41. if req.Api != "" {
  42. query = query.Where("wl.api = ?", strings.TrimSpace(req.Api))
  43. }
  44. if req.Name != "" {
  45. query = query.Where("wl.name = ?", strings.TrimSpace(req.Name))
  46. }
  47. if req.RuleId != 0 {
  48. query = query.Where("wl.rule_id = ?", req.RuleId)
  49. }
  50. if len(req.HostIds) > 0 {
  51. query = query.Where("wl.host_id IN ?", req.HostIds)
  52. }
  53. if req.UserAgent != "" {
  54. query = query.Where("wl.user_agent = ?", strings.TrimSpace(req.UserAgent))
  55. }
  56. if len(req.ApiNames) > 0 {
  57. query = query.Where("wl.api_name IN ?", req.ApiNames)
  58. }
  59. if len(req.ApiTypes) > 0 {
  60. query = query.Where("wl.api_type IN ?", req.ApiTypes)
  61. }
  62. if req.StartTime != "" {
  63. query = query.Where("wl.created_at > ?", strings.TrimSpace(req.StartTime))
  64. }
  65. if req.EndTime != "" {
  66. query = query.Where("wl.created_at < ?", strings.TrimSpace(req.EndTime))
  67. }
  68. return query
  69. }
  70. func (r *wafLogRepository) GetWafLog(ctx context.Context, id int64) (*model.WafLog, error) {
  71. var res model.WafLog
  72. return &res, r.DBWithName(ctx,"admin").Where("id = ?", id).First(&res).Error
  73. }
  74. func (r *wafLogRepository) GetWafLogList(ctx context.Context, req adminApi.SearchWafLogParams) (*v1.PaginatedResponse[model.WafLog], error) {
  75. var res []model.WafLog
  76. var total int64
  77. query := r.DBWithName(ctx,"admin").Model(&model.WafLog{})
  78. if req.RequestIp != "" {
  79. trimmedName := strings.TrimSpace(req.RequestIp)
  80. query = query.Where("request_ip LIKE CONCAT('%', ?, '%')", trimmedName)
  81. }
  82. if req.Uid != 0 {
  83. query = query.Where("uid = ?", req.Uid)
  84. }
  85. if req.Api != "" {
  86. trimmedName := strings.TrimSpace(req.Api)
  87. query = query.Where("api LIKE CONCAT('%', ?, '%')", trimmedName)
  88. }
  89. if req.Name != "" {
  90. trimmedName := strings.TrimSpace(req.Name)
  91. query = query.Where("name LIKE CONCAT('%', ?, '%')", trimmedName)
  92. }
  93. if req.RuleId != 0 {
  94. query = query.Where("rule_id = ?", req.RuleId)
  95. }
  96. if req.HostId != 0 {
  97. query = query.Where("host_id = ?", req.HostId)
  98. }
  99. if req.Api != "" {
  100. trimmedName := strings.TrimSpace(req.Api)
  101. query = query.Where("api LIKE CONCAT('%', ?, '%')", trimmedName)
  102. }
  103. if req.UserAgent != "" {
  104. trimmedName := strings.TrimSpace(req.UserAgent)
  105. query = query.Where("user_agent LIKE CONCAT('%', ?, '%')", trimmedName)
  106. }
  107. if req.ApiName != "" {
  108. trimmedName := strings.TrimSpace(req.ApiName)
  109. query = query.Where("api_name LIKE CONCAT('%', ?, '%')", trimmedName)
  110. }
  111. if req.ApiType != "" {
  112. query = query.Where("api_type = ?", req.ApiType)
  113. }
  114. if req.Column != "" {
  115. query = query.Order(req.Column + " " + req.Order)
  116. }
  117. if err := query.Count(&total).Error; err != nil {
  118. return nil, err
  119. }
  120. page := req.Current
  121. pageSize := req.PageSize
  122. if page <= 0 {
  123. page = 1
  124. }
  125. if pageSize <= 0 {
  126. pageSize = 10
  127. } else if pageSize > 100 {
  128. pageSize = 100
  129. }
  130. offset := (page - 1) * pageSize
  131. result := query.Offset(offset).Limit(pageSize).Find(&res)
  132. if result.Error != nil {
  133. return nil, result.Error
  134. }
  135. return &v1.PaginatedResponse[model.WafLog]{
  136. Records: res,
  137. Page: page,
  138. PageSize: pageSize,
  139. Total: total,
  140. TotalPages: int(math.Ceil(float64(total) / float64(pageSize))),
  141. }, nil
  142. }
  143. func (r *wafLogRepository) AddWafLog(ctx context.Context, log *model.WafLog) error {
  144. return r.DBWithName(ctx,"admin").Create(log).Error
  145. }
  146. func (r *wafLogRepository) BatchAddWafLog(ctx context.Context, logs []*model.WafLog) error {
  147. if len(logs) == 0 {
  148. return nil
  149. }
  150. return r.DBWithName(ctx, "admin").CreateInBatches(logs, len(logs)).Error
  151. }
  152. func (r *wafLogRepository) ExportWafLog(ctx context.Context, req adminApi.ExportWafLog) ([]model.WafLogWithGatewayIP, error) {
  153. return r.ExportWafLogWithPagination(ctx, req, 0, 0)
  154. }
  155. // ExportWafLogWithPagination 使用子查询获取每条日志在当时时间点的正确网关组IP
  156. func (r *wafLogRepository) ExportWafLogWithPagination(ctx context.Context, req adminApi.ExportWafLog, page, pageSize int) ([]model.WafLogWithGatewayIP, error) {
  157. var res []model.WafLogWithGatewayIP
  158. // 1. 使用辅助函数构建基础查询
  159. query := r.buildExportQuery(ctx, req)
  160. // 2. 构建子查询
  161. subQuery := r.DBWithName(ctx, "admin").Model(&model.WafLog{}).
  162. Select("extra_data").
  163. Where("api_name = ?", "分配网关组").
  164. Where("host_id = wl.host_id").
  165. Where("uid = wl.uid").
  166. Where("created_at <= wl.created_at").
  167. Order("created_at DESC").
  168. Limit(1)
  169. // 3. 添加 Select 和分页
  170. query = query.Select("wl.*, (?) as gateway_ip_data", subQuery)
  171. if page > 0 && pageSize > 0 {
  172. offset := (page - 1) * pageSize
  173. query = query.Offset(offset).Limit(pageSize)
  174. }
  175. // 4. 执行查询
  176. if err := query.Find(&res).Error; err != nil {
  177. if err == gorm.ErrRecordNotFound {
  178. return []model.WafLogWithGatewayIP{}, nil
  179. }
  180. return nil, err
  181. }
  182. return res, nil
  183. }
  184. // GetWafLogExportCount 获取导出数据总数(已优化)
  185. func (r *wafLogRepository) GetWafLogExportCount(ctx context.Context, req adminApi.ExportWafLog) (int, error) {
  186. var count int64
  187. // 直接复用 buildExportQuery 来构建查询
  188. query := r.buildExportQuery(ctx, req)
  189. if err := query.Count(&count).Error; err != nil {
  190. return 0, err
  191. }
  192. return int(count), nil
  193. }