mirror of https://github.com/MISP/PyMISP
fix: [exportpdf] Add suggestions (UX)
parent
ead9cec7d3
commit
b2c5477cd9
|
@ -27,7 +27,7 @@ try:
|
||||||
from reportlab.lib.utils import ImageReader
|
from reportlab.lib.utils import ImageReader
|
||||||
from reportlab.lib.pagesizes import A4
|
from reportlab.lib.pagesizes import A4
|
||||||
|
|
||||||
from reportlab.platypus import SimpleDocTemplate, Paragraph, PageBreak, Spacer, Table, TableStyle, Flowable, Image
|
from reportlab.platypus import SimpleDocTemplate, Paragraph, PageBreak, Spacer, Table, TableStyle, Flowable, Image, Indenter
|
||||||
|
|
||||||
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
|
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
|
||||||
from reportlab.lib.units import mm
|
from reportlab.lib.units import mm
|
||||||
|
@ -130,6 +130,8 @@ moduleconfig = ["MISP_base_url_for_dynamic_link", "MISP_name_for_metadata", "Act
|
||||||
# == Row colors of the table (alternating) ==
|
# == Row colors of the table (alternating) ==
|
||||||
EVEN_COLOR = colors.whitesmoke
|
EVEN_COLOR = colors.whitesmoke
|
||||||
ODD_COLOR = colors.lightgrey
|
ODD_COLOR = colors.lightgrey
|
||||||
|
EVEN_COLOR_GALAXY = colors.powderblue
|
||||||
|
ODD_COLOR_GALAXY = colors.lavenderblush
|
||||||
|
|
||||||
# == Lines parameters of the table ==
|
# == Lines parameters of the table ==
|
||||||
LINE_COLOR = colors.lightslategray
|
LINE_COLOR = colors.lightslategray
|
||||||
|
@ -163,15 +165,17 @@ ROW_HEIGHT_FOR_TAGS = 4 * mm # 4.5 * mm (a bit too short to allow vertical alig
|
||||||
# == Whole document margins and size ==
|
# == Whole document margins and size ==
|
||||||
PAGESIZE = A4 # (140 * mm, 216 * mm) # width, height
|
PAGESIZE = A4 # (140 * mm, 216 * mm) # width, height
|
||||||
BASE_MARGIN = 5 * mm # Create a list here to specify each row separately
|
BASE_MARGIN = 5 * mm # Create a list here to specify each row separately
|
||||||
|
INDENT_SIZE = 6 * mm # The Indentation of attribute from object, etc.
|
||||||
|
INDENT_SIZE_HEADING = 3 * mm # The Indentation of attribute from object, etc.
|
||||||
|
|
||||||
# == Parameters for error handling for content too long to fit on a page ==
|
# == Parameters for error handling for content too long to fit on a page ==
|
||||||
FRAME_MAX_HEIGHT = 500 # 650 # Ad hoc value for a A4 page
|
FRAME_MAX_HEIGHT = 200*mm # 500 # Ad hoc value for a A4 page
|
||||||
FRAME_MAX_WIDTH = 356
|
FRAME_MAX_WIDTH = 145*mm - INDENT_SIZE # 356
|
||||||
STR_TOO_LONG_WARNING = "<br/><b><font color=red>[Too long to fit on a single page. Cropped]</font></b>"
|
STR_TOO_LONG_WARNING = "<br/><b><font color=red>[Too long to fit on a single page. Cropped]</font></b>"
|
||||||
|
|
||||||
# == Parameters for error handling for image too big to fit on a page ==
|
# == Parameters for error handling for image too big to fit on a page ==
|
||||||
FRAME_PICTURE_MAX_WIDTH = 88 * mm
|
FRAME_PICTURE_MAX_HEIGHT = 200*mm # 195 * mm
|
||||||
FRAME_PICTURE_MAX_HEIGHT = 195 * mm
|
FRAME_PICTURE_MAX_WIDTH = 145*mm - INDENT_SIZE # 88 * mm
|
||||||
|
|
||||||
# == Parameters for links management ==
|
# == Parameters for links management ==
|
||||||
LINK_TYPE = "link" # Name of the type that define 'good' links
|
LINK_TYPE = "link" # Name of the type that define 'good' links
|
||||||
|
@ -254,7 +258,7 @@ def uuid_to_url(baseurl, uuid):
|
||||||
return baseurl + "events/view/" + uuid
|
return baseurl + "events/view/" + uuid
|
||||||
|
|
||||||
|
|
||||||
def create_flowable_table_from_data(data, col_w=COL_WIDTHS, color_alternation=None, line_alternation=None):
|
def create_flowable_table_from_data(data, col_w=COL_WIDTHS, color_alternation=None, line_alternation=None, galaxy_colors=False):
|
||||||
'''
|
'''
|
||||||
Given a list of flowables items (2D/list of list), creates a Table with styles.
|
Given a list of flowables items (2D/list of list), creates a Table with styles.
|
||||||
:param data: list of list of items (flowables is better)
|
:param data: list of list of items (flowables is better)
|
||||||
|
@ -268,7 +272,7 @@ def create_flowable_table_from_data(data, col_w=COL_WIDTHS, color_alternation=No
|
||||||
# rowHeights=ROW_HEIGHT if you want a fixed height. /!\ Problems with paragraphs that are spreading everywhere
|
# rowHeights=ROW_HEIGHT if you want a fixed height. /!\ Problems with paragraphs that are spreading everywhere
|
||||||
|
|
||||||
# Create styles and set parameters
|
# Create styles and set parameters
|
||||||
alternate_colors_style = alternate_colors_style_generator(data,color_alternation)
|
alternate_colors_style = alternate_colors_style_generator(data,color_alternation, galaxy_colors)
|
||||||
lines_style = lines_style_generator(data,line_alternation)
|
lines_style = lines_style_generator(data,line_alternation)
|
||||||
general_style = general_style_generator()
|
general_style = general_style_generator()
|
||||||
|
|
||||||
|
@ -278,7 +282,7 @@ def create_flowable_table_from_data(data, col_w=COL_WIDTHS, color_alternation=No
|
||||||
return curr_table
|
return curr_table
|
||||||
|
|
||||||
|
|
||||||
def alternate_colors_style_generator(data, color_alternation):
|
def alternate_colors_style_generator(data, color_alternation, galaxy_colors=True):
|
||||||
'''
|
'''
|
||||||
Create a style, applicable on a table that will be built with parameter's data, with alternated
|
Create a style, applicable on a table that will be built with parameter's data, with alternated
|
||||||
background color for each line.
|
background color for each line.
|
||||||
|
@ -296,20 +300,20 @@ def alternate_colors_style_generator(data, color_alternation):
|
||||||
# For each line, generate a tuple giving to a line a color
|
# For each line, generate a tuple giving to a line a color
|
||||||
for each in range(data_len):
|
for each in range(data_len):
|
||||||
if each % 2 == 0:
|
if each % 2 == 0:
|
||||||
bg_color = EVEN_COLOR
|
bg_color = EVEN_COLOR if not galaxy_colors else EVEN_COLOR_GALAXY
|
||||||
else:
|
else:
|
||||||
bg_color = ODD_COLOR
|
bg_color = ODD_COLOR if not galaxy_colors else ODD_COLOR_GALAXY
|
||||||
color_list.append(('BACKGROUND', (0, each), (-1, each), bg_color))
|
color_list.append(('BACKGROUND', (0, each), (-1, each), bg_color))
|
||||||
else:
|
else:
|
||||||
if data_len > len(color_alternation) :
|
# if data_len > len(color_alternation) :
|
||||||
logger.warning("Line alternation for PDF display isn't correctly set. Looping on given values only.")
|
# logger.warning("Line alternation for PDF display isn't correctly set. Looping on given values only.")
|
||||||
|
|
||||||
# For each line, generate a tuple giving to a line a color
|
# For each line, generate a tuple giving to a line a color
|
||||||
for each in range(data_len):
|
for each in range(data_len):
|
||||||
if color_alternation[each%len(color_alternation)] % 2 == 0:
|
if color_alternation[each%len(color_alternation)] % 2 == 0:
|
||||||
bg_color = EVEN_COLOR
|
bg_color = EVEN_COLOR if not galaxy_colors else EVEN_COLOR_GALAXY
|
||||||
else:
|
else:
|
||||||
bg_color = ODD_COLOR
|
bg_color = ODD_COLOR if not galaxy_colors else ODD_COLOR_GALAXY
|
||||||
color_list.append(('BACKGROUND', (0, each), (-1, each), bg_color))
|
color_list.append(('BACKGROUND', (0, each), (-1, each), bg_color))
|
||||||
|
|
||||||
return color_list
|
return color_list
|
||||||
|
@ -338,8 +342,8 @@ def lines_style_generator(data, line_alternation):
|
||||||
# Do nothing
|
# Do nothing
|
||||||
return lines_list
|
return lines_list
|
||||||
else:
|
else:
|
||||||
if data_len > len(line_alternation) :
|
# if data_len > len(line_alternation) :
|
||||||
logger.warning("Line alternation for PDF display isn't correctly set. Looping on given values only.")
|
# logger.warning("Line alternation for PDF display isn't correctly set. Looping on given values only.")
|
||||||
|
|
||||||
# For each line, generate a tuple giving to a line a color
|
# For each line, generate a tuple giving to a line a color
|
||||||
for each in range(data_len):
|
for each in range(data_len):
|
||||||
|
@ -784,7 +788,6 @@ class Value_Formatter():
|
||||||
tmp_text = ""
|
tmp_text = ""
|
||||||
|
|
||||||
if is_safe_dict_attribute(misp_cluster, item[1]):
|
if is_safe_dict_attribute(misp_cluster, item[1]):
|
||||||
print(misp_cluster[item[1]])
|
|
||||||
tmp_text += safe_string(misp_cluster[item[1]])
|
tmp_text += safe_string(misp_cluster[item[1]])
|
||||||
|
|
||||||
#if is_safe_dict_attribute(misp_cluster, item[3]) :
|
#if is_safe_dict_attribute(misp_cluster, item[3]) :
|
||||||
|
@ -1020,7 +1023,10 @@ class Attributes():
|
||||||
# There is some attributes for this object
|
# There is some attributes for this object
|
||||||
for item in getattr(misp_event, "Attribute"):
|
for item in getattr(misp_event, "Attribute"):
|
||||||
# you can use a spacer instead of title to separate paragraph: flowable_table.append(Spacer(1, 5 * mm))
|
# you can use a spacer instead of title to separate paragraph: flowable_table.append(Spacer(1, 5 * mm))
|
||||||
|
flowable_table.append(Indenter(left=INDENT_SIZE_HEADING))
|
||||||
flowable_table.append(Paragraph("Attribute #" + str(i+OFFSET), self.sample_style_sheet['Heading4']))
|
flowable_table.append(Paragraph("Attribute #" + str(i+OFFSET), self.sample_style_sheet['Heading4']))
|
||||||
|
flowable_table.append(Indenter(left=-INDENT_SIZE_HEADING))
|
||||||
|
|
||||||
flowable_table += self.create_flowable_table_from_one_attribute(item)
|
flowable_table += self.create_flowable_table_from_one_attribute(item)
|
||||||
i += 1
|
i += 1
|
||||||
else:
|
else:
|
||||||
|
@ -1092,11 +1098,14 @@ class Attributes():
|
||||||
|
|
||||||
flowable_table.append(create_flowable_table_from_data(data))
|
flowable_table.append(create_flowable_table_from_data(data))
|
||||||
|
|
||||||
|
|
||||||
# Galaxies
|
# Galaxies
|
||||||
item = ["Related Galaxies", 'Galaxy', "None"]
|
item = ["Related Galaxies", 'Galaxy', "None"]
|
||||||
if is_safe_attribute_table(misp_attribute, item[1]) :
|
if is_safe_attribute_table(misp_attribute, item[1]) :
|
||||||
curr_Galaxy = Galaxy(self.config, self.value_formatter)
|
curr_Galaxy = Galaxy(self.config, self.value_formatter)
|
||||||
|
flowable_table.append(Indenter(left=INDENT_SIZE))
|
||||||
flowable_table += curr_Galaxy.get_galaxy_value(misp_attribute, item)
|
flowable_table += curr_Galaxy.get_galaxy_value(misp_attribute, item)
|
||||||
|
flowable_table.append(Indenter(left=-INDENT_SIZE))
|
||||||
|
|
||||||
return flowable_table
|
return flowable_table
|
||||||
|
|
||||||
|
@ -1234,7 +1243,9 @@ class Object():
|
||||||
# There is a list of objects
|
# There is a list of objects
|
||||||
for item in getattr(misp_event, "Object"):
|
for item in getattr(misp_event, "Object"):
|
||||||
# you can use a spacer instead of title to separate paragraph: flowable_table.append(Spacer(1, 5 * mm))
|
# you can use a spacer instead of title to separate paragraph: flowable_table.append(Spacer(1, 5 * mm))
|
||||||
|
flowable_table.append(Indenter(left=INDENT_SIZE_HEADING))
|
||||||
flowable_table.append(Paragraph("Object #" + str(i+OFFSET), self.sample_style_sheet['Heading3']))
|
flowable_table.append(Paragraph("Object #" + str(i+OFFSET), self.sample_style_sheet['Heading3']))
|
||||||
|
flowable_table.append(Indenter(left=-INDENT_SIZE_HEADING))
|
||||||
flowable_table += self.create_flowable_table_from_one_object(item, config)
|
flowable_table += self.create_flowable_table_from_one_object(item, config)
|
||||||
i += 1
|
i += 1
|
||||||
else:
|
else:
|
||||||
|
@ -1281,7 +1292,9 @@ class Object():
|
||||||
# Handle all the attributes
|
# Handle all the attributes
|
||||||
if is_safe_attribute(misp_object, "Attribute"):
|
if is_safe_attribute(misp_object, "Attribute"):
|
||||||
curr_attributes = Attributes(self.config, self.value_formatter)
|
curr_attributes = Attributes(self.config, self.value_formatter)
|
||||||
|
data.append(Indenter(left=INDENT_SIZE))
|
||||||
data += curr_attributes.create_flowable_table_from_attributes(misp_object)
|
data += curr_attributes.create_flowable_table_from_attributes(misp_object)
|
||||||
|
data.append(Indenter(left=-INDENT_SIZE))
|
||||||
|
|
||||||
# Add a page break at the end of an object
|
# Add a page break at the end of an object
|
||||||
data.append(PageBreak())
|
data.append(PageBreak())
|
||||||
|
@ -1317,7 +1330,9 @@ class Galaxy():
|
||||||
if is_safe_attribute_table(misp_event, item[1]) and is_in_config(self.config, 3):
|
if is_safe_attribute_table(misp_event, item[1]) and is_in_config(self.config, 3):
|
||||||
galaxy_title = Paragraph(item[0], self.sample_style_sheet['Heading5'])
|
galaxy_title = Paragraph(item[0], self.sample_style_sheet['Heading5'])
|
||||||
|
|
||||||
|
flowable_table.append(Indenter(left=INDENT_SIZE_HEADING))
|
||||||
flowable_table.append(galaxy_title)
|
flowable_table.append(galaxy_title)
|
||||||
|
flowable_table.append(Indenter(left=-INDENT_SIZE_HEADING))
|
||||||
flowable_table += self.create_flowable_table_from_galaxies(misp_event)
|
flowable_table += self.create_flowable_table_from_galaxies(misp_event)
|
||||||
else :
|
else :
|
||||||
flowable_table.append(self.value_formatter.get_unoverflowable_paragraph(item[2]))
|
flowable_table.append(self.value_formatter.get_unoverflowable_paragraph(item[2]))
|
||||||
|
@ -1344,7 +1359,9 @@ class Galaxy():
|
||||||
|
|
||||||
txt_title = "Galaxy #" + str(i+OFFSET) + " - " + safe_string(curr_galaxy["name"])
|
txt_title = "Galaxy #" + str(i+OFFSET) + " - " + safe_string(curr_galaxy["name"])
|
||||||
galaxy_title = Paragraph(txt_title, self.sample_style_sheet['Heading6'])
|
galaxy_title = Paragraph(txt_title, self.sample_style_sheet['Heading6'])
|
||||||
|
flowable_table.append(Indenter(left=INDENT_SIZE_HEADING))
|
||||||
flowable_table.append(galaxy_title)
|
flowable_table.append(galaxy_title)
|
||||||
|
flowable_table.append(Indenter(left=-INDENT_SIZE_HEADING))
|
||||||
i += 1
|
i += 1
|
||||||
|
|
||||||
# Add metadata about the Galaxy
|
# Add metadata about the Galaxy
|
||||||
|
@ -1430,7 +1447,7 @@ class Galaxy_cluster():
|
||||||
# For each cluster
|
# For each cluster
|
||||||
tmp_data = self.create_flowable_table_from_one_galaxy_cluster(curr_cluster)
|
tmp_data = self.create_flowable_table_from_one_galaxy_cluster(curr_cluster)
|
||||||
tmp_flowable_table = []
|
tmp_flowable_table = []
|
||||||
tmp_flowable_table.append(create_flowable_table_from_data(tmp_data, col_w=SECOND_LEVEL_GALAXY_WIDTHS, color_alternation = CLUSTER_COLORS, line_alternation=[]))
|
tmp_flowable_table.append(create_flowable_table_from_data(tmp_data, col_w=SECOND_LEVEL_GALAXY_WIDTHS, color_alternation = CLUSTER_COLORS, line_alternation=[], galaxy_colors=True))
|
||||||
data.append([self.value_formatter.get_col1_paragraph(item[0], do_small=DO_SMALL_GALAXIES), tmp_flowable_table]) # Cluster #X - 3 lines
|
data.append([self.value_formatter.get_col1_paragraph(item[0], do_small=DO_SMALL_GALAXIES), tmp_flowable_table]) # Cluster #X - 3 lines
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
@ -1438,7 +1455,7 @@ class Galaxy_cluster():
|
||||||
data = [self.value_formatter.get_unoverflowable_paragraph("No galaxy cluster", do_small=DO_SMALL_GALAXIES)]
|
data = [self.value_formatter.get_unoverflowable_paragraph("No galaxy cluster", do_small=DO_SMALL_GALAXIES)]
|
||||||
|
|
||||||
flowable_table = []
|
flowable_table = []
|
||||||
flowable_table.append(create_flowable_table_from_data(data, col_w=FIRST_LEVEL_GALAXY_WIDTHS, color_alternation = CLUSTER_COLORS))
|
flowable_table.append(create_flowable_table_from_data(data, col_w=FIRST_LEVEL_GALAXY_WIDTHS, color_alternation = CLUSTER_COLORS, galaxy_colors=True))
|
||||||
|
|
||||||
return flowable_table
|
return flowable_table
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue