Skip to content

Commit 37b3e8e

Browse files
Add status and notes columns to CSV/Excel exports (#13970)
- Add 'status' column showing finding status (Active, Verified, etc.) - Add 'notes' column aggregating all public notes for each finding - Filter out private notes from exports for privacy compliance - Add prefetching for notes to avoid N+1 queries - Follow existing patterns for multiline field handling (NEWLINE for CSV, actual newlines for Excel) Fixes #8995
1 parent 56642f9 commit 37b3e8e

1 file changed

Lines changed: 44 additions & 2 deletions

File tree

dojo/reports/views.py

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from dateutil.relativedelta import relativedelta
88
from django.conf import settings
99
from django.core.exceptions import PermissionDenied
10+
from django.db.models import Prefetch
1011
from django.http import Http404, HttpRequest, HttpResponse, QueryDict
1112
from django.shortcuts import get_object_or_404, render
1213
from django.utils import timezone
@@ -28,7 +29,7 @@
2829
from dojo.finding.views import BaseListFindings
2930
from dojo.forms import ReportOptionsForm
3031
from dojo.labels import get_labels
31-
from dojo.models import Dojo_User, Endpoint, Engagement, Finding, Product, Product_Type, Test
32+
from dojo.models import Dojo_User, Endpoint, Engagement, Finding, Notes, Product, Product_Type, Test
3233
from dojo.reports.widgets import (
3334
CoverPage,
3435
CustomReportJsonForm,
@@ -642,7 +643,7 @@ def prefetch_related_findings_for_report(findings):
642643
"burprawrequestresponse_set",
643644
"endpoints",
644645
"tags",
645-
"notes",
646+
Prefetch("notes", queryset=Notes.objects.filter(private=False)),
646647
"files",
647648
"reporter",
648649
"mitigated_by",
@@ -815,6 +816,7 @@ def add_extra_values(self):
815816

816817
def get(self, request):
817818
findings, _obj = get_findings(request)
819+
findings = prefetch_related_findings_for_report(findings)
818820
self.findings = findings
819821
findings = self.add_findings_data()
820822
response = HttpResponse(content_type="text/csv")
@@ -850,6 +852,8 @@ def get(self, request):
850852
"endpoints",
851853
"vulnerability_ids",
852854
"tags",
855+
"status",
856+
"notes",
853857
))
854858
self.fields = fields
855859
self.add_extra_headers()
@@ -913,6 +917,20 @@ def get(self, request):
913917
tags_value = tags_value.removesuffix("; ")
914918
fields.append(tags_value)
915919

920+
# Status
921+
status_value = finding.status()
922+
fields.append(status_value)
923+
924+
# Notes
925+
notes_value = ""
926+
for note in finding.notes.filter(private=False):
927+
note_entry = note.entry.replace("\n", " NEWLINE ").replace("\r", "")
928+
notes_value += f"{note_entry}; "
929+
notes_value = notes_value.removesuffix("; ")
930+
if len(notes_value) > EXCEL_CHAR_LIMIT:
931+
notes_value = notes_value[:EXCEL_CHAR_LIMIT - 3] + "..."
932+
fields.append(notes_value)
933+
916934
self.fields = fields
917935
self.finding = finding
918936
self.add_extra_values()
@@ -935,6 +953,7 @@ def add_extra_values(self):
935953

936954
def get(self, request):
937955
findings, _obj = get_findings(request)
956+
findings = prefetch_related_findings_for_report(findings)
938957
self.findings = findings
939958
findings = self.add_findings_data()
940959
workbook = Workbook()
@@ -990,6 +1009,12 @@ def get(self, request):
9901009
cell = worksheet.cell(row=row_num, column=col_num, value="tags")
9911010
cell.font = font_bold
9921011
col_num += 1
1012+
cell = worksheet.cell(row=row_num, column=col_num, value="status")
1013+
cell.font = font_bold
1014+
col_num += 1
1015+
cell = worksheet.cell(row=row_num, column=col_num, value="notes")
1016+
cell.font = font_bold
1017+
col_num += 1
9931018
self.row_num = row_num
9941019
self.col_num = col_num
9951020
self.add_extra_headers()
@@ -1056,6 +1081,23 @@ def get(self, request):
10561081
tags_value = tags_value.removesuffix("; \n")
10571082
worksheet.cell(row=row_num, column=col_num, value=tags_value)
10581083
col_num += 1
1084+
1085+
# Status
1086+
status_value = finding.status()
1087+
worksheet.cell(row=row_num, column=col_num, value=status_value)
1088+
col_num += 1
1089+
1090+
# Notes
1091+
notes_value = ""
1092+
for note in finding.notes.filter(private=False):
1093+
note_entry = note.entry.replace("\r", "")
1094+
notes_value += f"{note_entry}; \n"
1095+
notes_value = notes_value.removesuffix("; \n")
1096+
if len(notes_value) > EXCEL_CHAR_LIMIT:
1097+
notes_value = notes_value[:EXCEL_CHAR_LIMIT - 3] + "..."
1098+
worksheet.cell(row=row_num, column=col_num, value=notes_value)
1099+
col_num += 1
1100+
10591101
self.col_num = col_num
10601102
self.row_num = row_num
10611103
self.finding = finding

0 commit comments

Comments
 (0)