Skip to content

Feat/multi format audit report export#3238

Open
LordofAvernus wants to merge 10 commits intomainfrom
feat/multi-format-audit-report-export
Open

Feat/multi format audit report export#3238
LordofAvernus wants to merge 10 commits intomainfrom
feat/multi-format-audit-report-export

Conversation

@LordofAvernus
Copy link
Copy Markdown
Collaborator

@LordofAvernus LordofAvernus commented Apr 10, 2026

User description

关联的 issue

描述你的变更

https://github.com/actiontech/sqle-ee/issues/2689

确认项(pr提交后操作)

Tip

请在指定复审人之前,确认并完成以下事项,完成后✅


  • 我已完成自测
  • 我已记录完整日志方便进行诊断
  • 我已在关联的issue里补充了实现方案
  • 我已在关联的issue里补充了测试影响面
  • 我已确认了变更的兼容性,如果不兼容则在issue里标记 not_compatible
  • 我已确认了是否要更新文档,如果要更新则在issue里标记 need_update_doc


Description

  • 新增构建审核报告数据及国际化标签的函数

  • 添加 CSV 与 HTML 报告生成器及大量单元测试

  • 修改下载报告接口支持 export_format 参数传入导出格式

  • 更新接口文档与本地化文件,新增报告相关说明


Diagram Walkthrough

flowchart LR
  A["下载报告接口更新"] -- "解析 export_format 参数" --> B["构建审核报告数据"]
  B -- "传递数据" --> C["CSV报告生成器"]
  B -- "传递数据" --> D["HTML报告生成器"]
  C -- "调用 CSVBuilder 生成报告" --> E["生成 CSV 文件"]
  D -- "使用 html/template 渲染" --> F["生成 HTML 文件"]
Loading

File Walkthrough

Relevant files
Enhancement
8 files
report_data_builder.go
新增构建审核报告数据、提取规则和排序统计函数                                                                     
+242/-0 
task.go
更新下载报告接口增加 export_format 参数处理                                                       
+16/-45 
report_csv.go
新增 CSV 格式报告生成器实现及接口方法                                                                       
+75/-0   
report_generator.go
定义审核报告数据模型及报告生成器接口                                                                             
+112/-0 
report_generator_ce.go
添加 CE 版报告导出入口及格式支持判断                                                                         
+30/-0   
report_html.go
新增 HTML 报告生成器,使用模板防止 XSS                                                                 
+51/-0   
report_html_template.go
实现嵌入 HTML 模板的读取及解析功能                                                                         
+17/-0   
file.go
增加导出格式常量及 NormalizeExportFormatStr 函数                                       
+24/-0   
Tests
3 files
report_data_builder_test.go
添加审核报告数据功能的单元测试                                                                                   
+451/-0 
report_generator_ce_test.go
编写 CE 版报告导出相关测试,验证格式限制                                                                     
+111/-0 
report_generator_test.go
添加报告生成器(CSV/HTML)综合测试用例                                                                   
+754/-0 
Documentation
7 files
docs.go
更新 API 文档中报告导出参数说明                                                                             
+8/-1     
message_zh.go
新增报告相关国际化标签定义                                                                                       
+20/-0   
swagger.json
更新 Swagger 文档中导出报告接口描述                                                                     
+8/-1     
swagger.yaml
修改 Swagger YAML,新增 export_format 参数说明                                       
+6/-1     
active.en.toml
添加英文版报告标签国际化配置                                                                                     
+16/-0   
active.zh.toml
添加中文版报告标签国际化配置                                                                                     
+16/-0   
audit_report.html
新增 HTML 报告模板,包含多模块报告样式                                                                     
+280/-0 

…or interface

Add backend infrastructure for multi-format audit report export:
- Extend ExportFormat enum with HTML/PDF/WORD constants
- Add NormalizeExportFormatStr function for string-based format normalization
- Define AuditReportData, AuditSummary, AuditStatistics, LevelCount, RuleHit,
  AuditSQLItem, and ReportLabels data model structs
- Define ReportGenerator interface with Generate and Format methods
- Add CSVHeaders() and ToCSVRow() helper methods for CSV export
- Add unit tests for NormalizeExportFormatStr with map case pattern
Implement CSVReportGenerator that reuses the existing CSVBuilder to
generate CSV audit reports via the ReportGenerator interface. Add
comprehensive unit tests covering normal data, empty SQL list, and
special character escaping (comma, newline, double quote).
…ests

- Add self-contained HTML report template (templates/audit_report.html) with
  4 content modules: audit summary, result statistics, problem SQL list, and
  rule hit statistics. All text uses Go template i18n variables, CSS is inlined,
  SQL displayed in <pre> tags, logo supports base64 embedding.
- Add report_html_template.go using embed.FS to embed the HTML template file.
- Add report_html.go implementing HTMLReportGenerator with html/template for
  automatic XSS prevention via HTML escaping. Content-Type: text/html,
  filename format: SQL_audit_report_{instance}_{taskId}.html.
- Add 4 unit tests: Normal (ContentType, HTML tags, SQL content, labels),
  XSSPrevention (script/img tags escaped), EmptyData (empty SQL list renders),
  LargeData (10000 SQL items performance check).
… export

Refactor the DownloadTaskSQLReportFile API handler to support exporting
audit reports in multiple formats (CSV, HTML, PDF, WORD) via the new
export_format query parameter. Default to CSV for backward compatibility.

Key changes:
- Add BuildAuditReportData function in report_data_builder.go that
  converts Task + SQL data into AuditReportData (placed in controller
  layer to avoid circular dependency between utils and model packages)
- Refactor DownloadTaskSQLReportFile to use BuildAuditReportData and
  ExportAuditReport for format-agnostic report generation
- Add 16 new i18n locale messages for report labels (zh/en TOML + Go vars)
- Update Swagger annotations with export_format parameter
- Add comprehensive unit tests for helper functions: toLevelCounts,
  toRuleHits, extractRuleInfo, buildReportLabels (13 test functions,
  map case pattern, covering normal/empty/nil/edge cases)

Requirement refs: REQ-6.1, REQ-6.2, REQ-6.4, REQ-NF-2.1, REQ-NF-3.1
Update swagger.json, swagger.yaml, and docs.go to include the new
export_format query parameter (type: string, default: csv) for the
/v1/tasks/audits/{task_id}/sql_report endpoint. Also update response
description from "sql report csv file" to "sql report file" to reflect
multi-format support.
@github-actions
Copy link
Copy Markdown

github-actions bot commented Apr 10, 2026

PR Reviewer Guide 🔍

(Review updated until commit 0fc0407)

⏱️ Estimated effort to review: 4 🔵🔵🔵🔵⚪
🧪 PR contains tests
🔒 No security concerns identified
⚡ Recommended focus areas for review

时间一致性

在构建报告数据时分别调用了 time.Now() 来生成审核时间和报告生成时间,这可能导致两个时间值不一致,建议统一一次性获取当前时间然后复用。

auditTime := time.Now().Format("2006-01-02 15:04:05")
if task.CreatedAt.Year() > 1 {
	auditTime = task.CreatedAt.Format("2006-01-02 15:04:05")
}
参数规范

在 NormalizeExportFormatStr 函数中,对于无效的导出格式直接返回错误,需确认这是否符合向后兼容要求;如果需求允许,或可考虑默认回退到 CSV 格式以提升用户体验。

// NormalizeExportFormatStr 规范化导出格式参数(字符串版本)。
// 空字符串默认返回 CSV(向后兼容);无效格式返回错误。
// 支持 html/pdf/word/docx/excel/xlsx/csv 等输入的规范化。
func NormalizeExportFormatStr(format string) (ExportFormat, error) {
	switch strings.ToLower(strings.TrimSpace(format)) {
	case "html":
		return ExportFormatHTML, nil
	case "pdf":
		return ExportFormatPDF, nil
	case "word", "docx":
		return ExportFormatWORD, nil
	case "excel", "xlsx":
		return ExcelExportFormat, nil
	case "csv", "":
		return CsvExportFormat, nil
	default:
		return "", fmt.Errorf("unsupported export format: %s", format)
	}
}

@github-actions
Copy link
Copy Markdown

Failed to generate code suggestions for PR

@github-actions
Copy link
Copy Markdown

Persistent review updated to latest commit 2d973a0

@github-actions
Copy link
Copy Markdown

PR Code Suggestions ✨

No code suggestions found for the PR.

…tData function

Updated the BuildAuditReportData function to initialize sqlList and problemSQLs with a predefined capacity based on taskSQLsDetail length, improving performance and memory usage.
@github-actions
Copy link
Copy Markdown

Persistent review updated to latest commit 0fc0407

@github-actions
Copy link
Copy Markdown

Failed to generate code suggestions for PR

Comment on lines +175 to +194
// NormalizeExportFormatStr 规范化导出格式参数(字符串版本)。
// 空字符串默认返回 CSV(向后兼容);无效格式返回错误。
// 支持 html/pdf/word/docx/excel/xlsx/csv 等输入的规范化。
func NormalizeExportFormatStr(format string) (ExportFormat, error) {
switch strings.ToLower(strings.TrimSpace(format)) {
case "html":
return ExportFormatHTML, nil
case "pdf":
return ExportFormatPDF, nil
case "word", "docx":
return ExportFormatWORD, nil
case "excel", "xlsx":
return ExcelExportFormat, nil
case "csv", "":
return CsvExportFormat, nil
default:
return "", fmt.Errorf("unsupported export format: %s", format)
}
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ExportFormat也是导出格式的业务对象,应当移动到业务层

Comment on lines +110 to +111
// ReportType 返回生成器对应的导出格式
ReportType() utils.ExportFormat
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

目前这个接口没有被除了单元测试之外的地方用到

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

可以保留

// @Param task_id path string true "task id"
// @Param no_duplicate query boolean false "select unique (fingerprint and audit result) for task sql"
// @Success 200 file 1 "sql report csv file"
// @Param export_format query string false "export format: csv, html, pdf, word" default(csv)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里是不是应该加一个enum
参考:
// @param sort_field query string false "sort field" Enums(first_appear_timestamp,last_receive_timestamp,fp_count)
// @param sort_order query string false "sort order" Enums(asc,desc)

Comment on lines +10478 to 10484
{
"type": "string",
"description": "export format: csv, html, pdf, word",
"name": "export_format",
"in": "query",
"default": "csv"
}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

确实缺少枚举

Comment on lines +155 to +190
// toLevelCounts 将等级分布 map 转换为有序的 LevelCount 切片。
// 按 error > warn > notice > normal 顺序排列。
func toLevelCounts(dist map[string]int) []auditreport.LevelCount {
if len(dist) == 0 {
return []auditreport.LevelCount{}
}

levelOrder := map[string]int{
"error": 0,
"warn": 1,
"notice": 2,
"normal": 3,
}

result := make([]auditreport.LevelCount, 0, len(dist))
for level, count := range dist {
result = append(result, auditreport.LevelCount{
Level: level,
Count: count,
})
}

sort.Slice(result, func(i, j int) bool {
oi, ok := levelOrder[result[i].Level]
if !ok {
oi = 99
}
oj, ok := levelOrder[result[j].Level]
if !ok {
oj = 99
}
return oi < oj
})

return result
}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

可以移除,没必要这么复杂,一开始定义一个数组就可以了

levelCounts := []LevelCount{
{Level: "normal", Count: 0},
{Level: "notice", Count: 0},
{Level: "warn", Count: 0},
{Level: "error", Count: 0},
}

根据level类型,在对应下标的元素里面++,不需要在Map和Array/Slice之间杂耍

// LevelCount 等级统计
type LevelCount struct {
Level string json:"level" // normal/notice/warn/error
Count int json:"count"
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants