Add threshold for subtables
This commit is contained in:
parent
2d54c4f7f5
commit
40daa827c4
@ -161,27 +161,44 @@ p.cssvalid,p.htmlvalid {float:left;margin-right:20px}
|
|||||||
box-sizing: border-box; /* Adjust size calculations to include padding and borders */
|
box-sizing: border-box; /* Adjust size calculations to include padding and borders */
|
||||||
}
|
}
|
||||||
|
|
||||||
.Incoming.email.recipients, .Junk.mail.counts, .Geoip.results, .Qpsmtpd.codes.league.table, .Viruses.found {
|
.Incoming, .Junk, .Geoip, .Qpsmtpd, .Viruses {
|
||||||
flex: 0 1 calc(25% - 20px); /* Each table will take 25% of the width minus margins */
|
flex: 0 1 calc(25% - 20px); /* Each table will take 25% of the width minus margins */
|
||||||
margin: 10px; /* Margin for spacing */
|
margin: 10px; /* Margin for spacing */
|
||||||
box-sizing: border-box; /* Include padding and border in the element's total width and height */
|
box-sizing: border-box; /* Include padding and border in the element's total width and height */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Ensure tables adapt on smaller screens */
|
/* Ensure tables adapt on smaller screens */
|
||||||
@media (max-width: 1024px) {
|
/* Default styling for large screens (5 columns) */
|
||||||
.Incoming.email.recipients, .Junk.mail.counts, .Geoip.results, .Qpsmtpd.codes.league.table, .Viruses.found {
|
.Incoming, .Junk, .Geoip, .Qpsmtpd, .Viruses {
|
||||||
flex: 0 1 calc(33% - 20px); /* 33% width for medium screens (3 columns)*/
|
flex: 0 1 calc(20% - 20px); /* 20% width for 5 columns */
|
||||||
|
margin: 10px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 4 columns layout */
|
||||||
|
@media (max-width: 1600px) {
|
||||||
|
.Incoming, .Junk, .Geoip, .Qpsmtpd, .Viruses {
|
||||||
|
flex: 0 1 calc(25% - 20px); /* 25% width for 4 columns */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 768px) {
|
/* 3 columns layout */
|
||||||
.Incoming.email.recipients, .Junk.mail.counts, .Geoip.results, .Qpsmtpd.codes.league.table, .Viruses.found {
|
@media (max-width: 1200px) {
|
||||||
flex: 0 1 calc(50% - 20px); /* 50% width for smaller screens (2 columns)*/
|
.Incoming, .Junk, .Geoip, .Qpsmtpd, .Viruses {
|
||||||
|
flex: 0 1 calc(33.333% - 20px); /* 33.333% width for 3 columns */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 480px) {
|
/* 2 columns layout */
|
||||||
.Incoming.email.recipients, .Junk.mail.counts, .Geoip.results, .Qpsmtpd.codes.league.table, .Viruses.found {
|
@media (max-width: 600px) {
|
||||||
flex: 0 1 100%; /* 100% width for mobile screens (1 column) */
|
.Incoming, .Junk, .Geoip, .Qpsmtpd, .Viruses {
|
||||||
|
flex: 0 1 calc(50% - 20px); /* 50% width for 2 columns */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 1 column layout for mobile */
|
||||||
|
@media (max-width: 300px) {
|
||||||
|
.Incoming, .Junk, .Geoip, .Qpsmtpd, .Viruses {
|
||||||
|
flex: 0 1 100%; /* 100% width for 1 column */
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,5 +1,11 @@
|
|||||||
<div class="${title}">
|
<div class="${classname}">
|
||||||
<h2>${title}</h2>
|
<h2>${title}</h2>
|
||||||
|
<tal:block condition="threshold != 0">
|
||||||
|
<span class='greyed-out'>Display threshold set to ${threshold}%</span>
|
||||||
|
</tal:block>
|
||||||
|
<tal:block condition="threshold == 0">
|
||||||
|
<br>
|
||||||
|
</tal:block>
|
||||||
<table style="border-collapse:collapse;">
|
<table style="border-collapse:collapse;">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
|
@ -740,14 +740,15 @@ def split_timestamp_and_data(log_entry: str) -> list:
|
|||||||
#print(f"ts:{timestamp}")
|
#print(f"ts:{timestamp}")
|
||||||
return [timestamp, rest_of_line]
|
return [timestamp, rest_of_line]
|
||||||
|
|
||||||
def render_sub_table(table_title,table_headers,found_values,get_character=None):
|
def render_sub_table(table_title, table_headers, found_values, get_character=None, suppress_threshold=False):
|
||||||
#print(f"render_sub_table:{table_title} {found_values}")
|
|
||||||
#Check if any data provided
|
#Check if any data provided
|
||||||
if len(found_values) != 0:
|
if len(found_values) != 0:
|
||||||
# Get the total
|
# Get the total
|
||||||
|
original_total = 0 # Initialize total variable
|
||||||
if isinstance(found_values, dict):
|
if isinstance(found_values, dict):
|
||||||
# If found_values is a dictionary, we operate as previously
|
# If found_values is a dictionary, we operate as previously
|
||||||
total_sum = sum(found_values.values())
|
total_sum = sum(found_values.values())
|
||||||
|
original_total = total_sum
|
||||||
if not BadCountries:
|
if not BadCountries:
|
||||||
get_character = None
|
get_character = None
|
||||||
if get_character:
|
if get_character:
|
||||||
@ -761,6 +762,7 @@ def render_sub_table(table_title,table_headers,found_values,get_character=None):
|
|||||||
# If found_values is a list of values
|
# If found_values is a list of values
|
||||||
if all(isinstance(v, (int, float)) for v in found_values):
|
if all(isinstance(v, (int, float)) for v in found_values):
|
||||||
total_sum = sum(found_values)
|
total_sum = sum(found_values)
|
||||||
|
original_total = total_sum
|
||||||
sub_result = [(i, value,
|
sub_result = [(i, value,
|
||||||
f"{round(value / total_sum * 100, 2)}%") for i, value in enumerate(found_values)]
|
f"{round(value / total_sum * 100, 2)}%") for i, value in enumerate(found_values)]
|
||||||
# If found_values is a list of dictionaries
|
# If found_values is a list of dictionaries
|
||||||
@ -771,27 +773,12 @@ def render_sub_table(table_title,table_headers,found_values,get_character=None):
|
|||||||
|
|
||||||
# Calculate the total of the first numeric entry (index 1)
|
# Calculate the total of the first numeric entry (index 1)
|
||||||
total = sum(row[1] for row in sub_result)
|
total = sum(row[1] for row in sub_result)
|
||||||
|
original_total = total
|
||||||
|
|
||||||
# Append percentage of the total for each entry
|
# Append percentage of the total for each entry
|
||||||
for row in sub_result:
|
for row in sub_result:
|
||||||
percentage = f"{round(row[1] / total * 100, 2) if total else 0}%" # Handle division by zero
|
percentage = f"{round(row[1] / total * 100, 2) if total else 0}%" # Handle division by zero
|
||||||
row.append(percentage)
|
row.append(percentage)
|
||||||
|
|
||||||
# total_sum = sum(d.get('value', 0) for d in found_values) # Adjust 'value' if necessary
|
|
||||||
# if total_sum != 0:
|
|
||||||
# if get_character:
|
|
||||||
# sub_result = [(d.get('key', i), d.get('value', 0),
|
|
||||||
# f"{round(d.get('value', 0) / total_sum * 100, 2)}%",
|
|
||||||
# f"{get_character(d.get('key', i))}") for i, d in enumerate(found_values)]
|
|
||||||
# else:
|
|
||||||
# sub_result = [(d.get('key', i), d.get('value', 0),
|
|
||||||
# f"{round(d.get('value', 0) / total_sum * 100, 2)}%") for i, d in enumerate(found_values)]
|
|
||||||
# else:
|
|
||||||
# if get_character:
|
|
||||||
# sub_result = [(d.get('key', i), d.get('value', 0),
|
|
||||||
# f"{get_character(d.get('key', i))}") for i, d in enumerate(found_values)]
|
|
||||||
# else:
|
|
||||||
# sub_result = [(d.get('key', i), d.get('value', 0)) for i, d in enumerate(found_values)]
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
raise ValueError("found_values must be either a list of numbers or a list of dictionaries.")
|
raise ValueError("found_values must be either a list of numbers or a list of dictionaries.")
|
||||||
@ -799,6 +786,30 @@ def render_sub_table(table_title,table_headers,found_values,get_character=None):
|
|||||||
raise TypeError("found_values must be a dictionary or a list.")
|
raise TypeError("found_values must be a dictionary or a list.")
|
||||||
#print(f"Sub:{sub_result}")
|
#print(f"Sub:{sub_result}")
|
||||||
sub_result.sort(key=lambda x: float(x[1]), reverse=True) # Sort by percentage in descending order
|
sub_result.sort(key=lambda x: float(x[1]), reverse=True) # Sort by percentage in descending order
|
||||||
|
|
||||||
|
# Dynamic threshold calculation
|
||||||
|
if not suppress_threshold:
|
||||||
|
dynamic_threshold = max(1, 100 / (original_total**0.5)) if original_total > 0 else 0
|
||||||
|
dynamic_threshold = round(dynamic_threshold,1)
|
||||||
|
print(f"Threshold for {table_title} set to {dynamic_threshold}% ")
|
||||||
|
else:
|
||||||
|
dynamic_threshold=0
|
||||||
|
absolute_floor = 50 # Minimum absolute value threshold
|
||||||
|
|
||||||
|
# Filter results using early termination
|
||||||
|
filtered_sub_result = []
|
||||||
|
for row in sub_result:
|
||||||
|
value = row[1]
|
||||||
|
percentage = (value / original_total * 100) if original_total else 0
|
||||||
|
|
||||||
|
# Exit condition: below both thresholds
|
||||||
|
if percentage < dynamic_threshold and value < absolute_floor:
|
||||||
|
break
|
||||||
|
|
||||||
|
filtered_sub_result.append(row)
|
||||||
|
|
||||||
|
sub_result = filtered_sub_result # Keep only significant rows
|
||||||
|
|
||||||
sub_template_path = template_dir+'mailstats-sub-table.html.pt'
|
sub_template_path = template_dir+'mailstats-sub-table.html.pt'
|
||||||
# Load the template
|
# Load the template
|
||||||
with open(sub_template_path, 'r') as template_file:
|
with open(sub_template_path, 'r') as template_file:
|
||||||
@ -808,21 +819,26 @@ def render_sub_table(table_title,table_headers,found_values,get_character=None):
|
|||||||
template = PageTemplate(template_content)
|
template = PageTemplate(template_content)
|
||||||
# Render the template with the 2D array data and column headers
|
# Render the template with the 2D array data and column headers
|
||||||
try:
|
try:
|
||||||
rendered_html = template(array_2d=sub_result, column_headers=table_headers, title=table_title)
|
rendered_html = template(array_2d=sub_result, column_headers=table_headers,
|
||||||
|
title=table_title, classname=get_first_word(table_title),
|
||||||
|
threshold=dynamic_threshold)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise ValueError(f"{table_title}: A chameleon controller render error occurred: {e}")
|
raise ValueError(f"{table_title}: A chameleon controller render error occurred: {e}")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise ValueError(f"{table_title}: A chameleon controller template error occurred: {e}")
|
raise ValueError(f"{table_title}: A chameleon controller template error occurred: {e}")
|
||||||
else:
|
else:
|
||||||
rendered_html = f"<div class={table_title}><h2>{table_title}</h2>No data for {table_title}</div>"
|
rendered_html = f"<div class='{get_first_word(table_title)}'><h2>{table_title}</h2>No data for {table_title}</div>"
|
||||||
return rendered_html
|
return rendered_html
|
||||||
|
|
||||||
|
|
||||||
def get_character_in_reject_list(code):
|
def get_character_in_reject_list(code):
|
||||||
if code in BadCountries:
|
if code in BadCountries:
|
||||||
return "*"
|
return "*"
|
||||||
else:
|
else:
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
def get_first_word(text):
|
||||||
|
return text.split(None, 1)[0]
|
||||||
|
|
||||||
def read_html_from_file(filepath):
|
def read_html_from_file(filepath):
|
||||||
"""
|
"""
|
||||||
@ -1643,7 +1659,7 @@ if __name__ == "__main__":
|
|||||||
#virus codes
|
#virus codes
|
||||||
virus_headers = ["Virus",'Count','Percent']
|
virus_headers = ["Virus",'Count','Percent']
|
||||||
virus_title = 'Viruses found'
|
virus_title = 'Viruses found'
|
||||||
rendered_html = render_sub_table(virus_title,virus_headers,found_viruses)
|
rendered_html = render_sub_table(virus_title,virus_headers,found_viruses,suppress_threshold=True)
|
||||||
# Add it to the total
|
# Add it to the total
|
||||||
total_html = insert_string_after(total_html,rendered_html, "<!---Add in sub tables here -->")
|
total_html = insert_string_after(total_html,rendered_html, "<!---Add in sub tables here -->")
|
||||||
|
|
||||||
@ -1659,7 +1675,7 @@ if __name__ == "__main__":
|
|||||||
junk_mail_count_headers = ['Username','Count', 'Percent']
|
junk_mail_count_headers = ['Username','Count', 'Percent']
|
||||||
junk_mail_counts = scan_mail_users()
|
junk_mail_counts = scan_mail_users()
|
||||||
junk_mail_count_title = 'Junk mail counts'
|
junk_mail_count_title = 'Junk mail counts'
|
||||||
rendered_html = render_sub_table(junk_mail_count_title,junk_mail_count_headers,junk_mail_counts)
|
rendered_html = render_sub_table(junk_mail_count_title,junk_mail_count_headers,junk_mail_counts,suppress_threshold=True)
|
||||||
# Add it to the total
|
# Add it to the total
|
||||||
total_html = insert_string_after(total_html,rendered_html, "<!---Add in sub tables here -->")
|
total_html = insert_string_after(total_html,rendered_html, "<!---Add in sub tables here -->")
|
||||||
|
|
||||||
@ -1668,7 +1684,7 @@ if __name__ == "__main__":
|
|||||||
#print(f"{recipients_found}")
|
#print(f"{recipients_found}")
|
||||||
recipient_count_headers = ["Email",'Queued','Rejected','Spam tagged','Accepted Percent']
|
recipient_count_headers = ["Email",'Queued','Rejected','Spam tagged','Accepted Percent']
|
||||||
recipient_count_title = 'Incoming email recipients'
|
recipient_count_title = 'Incoming email recipients'
|
||||||
rendered_html = render_sub_table(recipient_count_title,recipient_count_headers,recipients_found)
|
rendered_html = render_sub_table(recipient_count_title,recipient_count_headers,recipients_found,suppress_threshold=True)
|
||||||
# Add it to the total
|
# Add it to the total
|
||||||
total_html = insert_string_after(total_html,rendered_html, "<!---Add in sub tables here -->")
|
total_html = insert_string_after(total_html,rendered_html, "<!---Add in sub tables here -->")
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user