Add in recipient email table
This commit is contained in:
parent
9be485a1a9
commit
372d2b45dd
@ -8,10 +8,9 @@
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr tal:repeat="item array_2d">
|
<tr tal:repeat="item array_2d">
|
||||||
<td tal:repeat="cell item">${cell}<span tal:condition="repeat.cell.index == 2">%</span></td>
|
<td tal:repeat="cell item">${cell}</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -174,6 +174,7 @@
|
|||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<!--
|
||||||
<p class="cssvalid">
|
<p class="cssvalid">
|
||||||
<a href="http://jigsaw.w3.org/css-validator/check/referer">
|
<a href="http://jigsaw.w3.org/css-validator/check/referer">
|
||||||
<img style="border:0;width:88px;height:31px"
|
<img style="border:0;width:88px;height:31px"
|
||||||
@ -187,6 +188,7 @@
|
|||||||
src="http://www.w3.org/Icons/valid-xhtml10"
|
src="http://www.w3.org/Icons/valid-xhtml10"
|
||||||
alt="Valid XHTML 1.0!" height="31" width="88" /></a>
|
alt="Valid XHTML 1.0!" height="31" width="88" /></a>
|
||||||
</p>
|
</p>
|
||||||
|
-->
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
@ -742,35 +742,78 @@ def split_timestamp_and_data(log_entry: str) -> list:
|
|||||||
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):
|
||||||
# Get the total
|
#print(f"render_sub_table:{table_title} {found_values}")
|
||||||
total_sum = sum(found_values.values())
|
#Check if any data provided
|
||||||
# and add in list with second element the percentage
|
if len(found_values) != 0:
|
||||||
# Create a list of tuples with each tuple containing (key, value, percentage)
|
# Get the total
|
||||||
if get_character:
|
if isinstance(found_values, dict):
|
||||||
sub_result = [(key, value,
|
# If found_values is a dictionary, we operate as previously
|
||||||
f"{round(value / total_sum * 100, 2)}",
|
total_sum = sum(found_values.values())
|
||||||
f"{get_character(key)}") for key, value in found_values.items()
|
if get_character:
|
||||||
]
|
sub_result = [(key, value,
|
||||||
else:
|
f"{round(value / total_sum * 100, 2)}%",
|
||||||
sub_result = [(key, value,
|
f"{get_character(key)}") for key, value in found_values.items()]
|
||||||
f"{round(value / total_sum * 100, 2)}") for key, value in found_values.items()
|
else:
|
||||||
]
|
sub_result = [(key, value,
|
||||||
|
f"{round(value / total_sum * 100, 2)}%" ) for key, value in found_values.items()]
|
||||||
|
elif isinstance(found_values, list):
|
||||||
|
# If found_values is a list of values
|
||||||
|
if all(isinstance(v, (int, float)) for v in found_values):
|
||||||
|
total_sum = sum(found_values)
|
||||||
|
sub_result = [(i, value,
|
||||||
|
f"{round(value / total_sum * 100, 2)}%") for i, value in enumerate(found_values)]
|
||||||
|
# If found_values is a list of dictionaries
|
||||||
|
elif all(isinstance(v, dict) for v in found_values):
|
||||||
|
# Example assumes first key is used for identification and others are numeric
|
||||||
|
# Convert to 2D array
|
||||||
|
sub_result = [list(entry.values()) for entry in found_values]
|
||||||
|
|
||||||
sub_result.sort(key=lambda x: float(x[2]), reverse=True) # Sort by percentage in descending order
|
# Calculate the total of the first numeric entry (index 1)
|
||||||
sub_template_path = template_dir+'mailstats-sub-table.html.pt'
|
total = sum(row[1] for row in sub_result)
|
||||||
# Load the template
|
|
||||||
with open(sub_template_path, 'r') as template_file:
|
# Append percentage of the total for each entry
|
||||||
template_content = template_file.read()
|
for row in sub_result:
|
||||||
# Create a Chameleon template instance
|
percentage = f"{round(row[1] / total * 100, 2) if total else 0}%" # Handle division by zero
|
||||||
try:
|
row.append(percentage)
|
||||||
template = PageTemplate(template_content)
|
|
||||||
# Render the template with the 2D array data and column headers
|
# 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:
|
||||||
|
raise ValueError("found_values must be either a list of numbers or a list of dictionaries.")
|
||||||
|
else:
|
||||||
|
raise TypeError("found_values must be a dictionary or a list.")
|
||||||
|
#print(f"Sub:{sub_result}")
|
||||||
|
sub_result.sort(key=lambda x: float(x[1]), reverse=True) # Sort by percentage in descending order
|
||||||
|
sub_template_path = template_dir+'mailstats-sub-table.html.pt'
|
||||||
|
# Load the template
|
||||||
|
with open(sub_template_path, 'r') as template_file:
|
||||||
|
template_content = template_file.read()
|
||||||
|
# Create a Chameleon template instance
|
||||||
try:
|
try:
|
||||||
rendered_html = template(array_2d=sub_result, column_headers=table_headers, title=table_title)
|
template = PageTemplate(template_content)
|
||||||
|
# Render the template with the 2D array data and column headers
|
||||||
|
try:
|
||||||
|
rendered_html = template(array_2d=sub_result, column_headers=table_headers, title=table_title)
|
||||||
|
except Exception as 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 render error occurred: {e}")
|
raise ValueError(f"{table_title}: A chameleon controller template error occurred: {e}")
|
||||||
except Exception as e:
|
else:
|
||||||
raise ValueError(f"{table_title}: A chameleon controller template error occurred: {e}")
|
rendered_html = f"<div class={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):
|
||||||
@ -923,6 +966,44 @@ def get_heading():
|
|||||||
header_str = header_str.replace("\n","<br />")
|
header_str = header_str.replace("\n","<br />")
|
||||||
return header_str
|
return header_str
|
||||||
|
|
||||||
|
def scan_mail_users():
|
||||||
|
#
|
||||||
|
# Count emails left in junkmail folders for each user
|
||||||
|
#
|
||||||
|
base_path = '/home/e-smith/files/users'
|
||||||
|
users_info = defaultdict(int)
|
||||||
|
|
||||||
|
# List of junk mail directories to check
|
||||||
|
junk_mail_directories = [
|
||||||
|
'Maildir/.Junk/cur',
|
||||||
|
'Maildir/.Junk/new',
|
||||||
|
'Maildir/.Junkmail/cur',
|
||||||
|
'Maildir/.Junkmail/new'
|
||||||
|
]
|
||||||
|
|
||||||
|
# Iterate through each user directory
|
||||||
|
for user in os.listdir(base_path):
|
||||||
|
user_path = os.path.join(base_path, user)
|
||||||
|
# Check if it is a directory
|
||||||
|
if os.path.isdir(user_path):
|
||||||
|
total_junk_count = 0
|
||||||
|
|
||||||
|
# Check each junk mail path and accumulate counts
|
||||||
|
for junk_dir in junk_mail_directories:
|
||||||
|
junk_mail_path = os.path.join(user_path, junk_dir)
|
||||||
|
|
||||||
|
# Check if the Junk directory actually exists
|
||||||
|
if os.path.exists(junk_mail_path):
|
||||||
|
try:
|
||||||
|
# Count the number of junk mail files in that directory
|
||||||
|
junk_count = len(os.listdir(junk_mail_path))
|
||||||
|
total_junk_count += junk_count
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error counting junk mails in {junk_mail_path} for user {user}: {e}")
|
||||||
|
if total_junk_count != 0:
|
||||||
|
users_info[user] = total_junk_count
|
||||||
|
return users_info
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
try:
|
try:
|
||||||
chameleon_version = pkg_resources.get_distribution("Chameleon").version
|
chameleon_version = pkg_resources.get_distribution("Chameleon").version
|
||||||
@ -949,7 +1030,7 @@ if __name__ == "__main__":
|
|||||||
datetime.strptime(analysis_date, '%Y-%m-%d')
|
datetime.strptime(analysis_date, '%Y-%m-%d')
|
||||||
except ValueError:
|
except ValueError:
|
||||||
print("Specify a valid date (yyyy-mm-dd) for the analysis")
|
print("Specify a valid date (yyyy-mm-dd) for the analysis")
|
||||||
(quit)()
|
quit(1)
|
||||||
|
|
||||||
anaysis_date_obj = datetime.strptime(analysis_date, '%Y-%m-%d')
|
anaysis_date_obj = datetime.strptime(analysis_date, '%Y-%m-%d')
|
||||||
noemailfile = args.emailfile.lower() == 'n'
|
noemailfile = args.emailfile.lower() == 'n'
|
||||||
@ -1109,6 +1190,8 @@ if __name__ == "__main__":
|
|||||||
virus_pattern = re.compile(r"Virus found: (.*)")
|
virus_pattern = re.compile(r"Virus found: (.*)")
|
||||||
found_viruses = defaultdict(int)
|
found_viruses = defaultdict(int)
|
||||||
|
|
||||||
|
recipients_found = []
|
||||||
|
|
||||||
found_qpcodes = defaultdict(int)
|
found_qpcodes = defaultdict(int)
|
||||||
qpcodes_pattern = re.compile(r"(\(.*\)).*'")
|
qpcodes_pattern = re.compile(r"(\(.*\)).*'")
|
||||||
i = 0;
|
i = 0;
|
||||||
@ -1240,6 +1323,7 @@ if __name__ == "__main__":
|
|||||||
hamavg += score
|
hamavg += score
|
||||||
hamcount += 1
|
hamcount += 1
|
||||||
#spamassasin rejects
|
#spamassasin rejects
|
||||||
|
Isqueuedspam = False;
|
||||||
if parsed_data.get('spam-status') is not None and isinstance(parsed_data['spam-status'], str):
|
if parsed_data.get('spam-status') is not None and isinstance(parsed_data['spam-status'], str):
|
||||||
if parsed_data['spam-status'].lower().startswith('yes'):
|
if parsed_data['spam-status'].lower().startswith('yes'):
|
||||||
#Extract other parameters from this string
|
#Extract other parameters from this string
|
||||||
@ -1259,6 +1343,7 @@ if __name__ == "__main__":
|
|||||||
columnCounts_2d[ColTotals][QuedSpam] += 1
|
columnCounts_2d[ColTotals][QuedSpam] += 1
|
||||||
spamavg += score
|
spamavg += score
|
||||||
spamqueuedcount += 1
|
spamqueuedcount += 1
|
||||||
|
Isqueuedspam = True #for recipient stats below
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -1281,6 +1366,26 @@ if __name__ == "__main__":
|
|||||||
else:
|
else:
|
||||||
found_qpcodes[parsed_data['action1']] += 1
|
found_qpcodes[parsed_data['action1']] += 1
|
||||||
|
|
||||||
|
#Log the recipients and deny or accept and spam-tagged counts
|
||||||
|
# Try to find an existing record for the email
|
||||||
|
email = parsed_data["from-email"] # Extract email
|
||||||
|
action = parsed_data["action"] # Extract action
|
||||||
|
#print(f"{email} {action}")
|
||||||
|
record = next((item for item in recipients_found if item['email'] == email), None)
|
||||||
|
if not record:
|
||||||
|
# If email is not in the array, we add it
|
||||||
|
record = {"email": email, "deny": 0, "accept": 0,"spam-tagged": 0}
|
||||||
|
recipients_found.append(record)
|
||||||
|
# Update the deny or accept count based on action
|
||||||
|
if action != "(queue)":
|
||||||
|
record["deny"] += 1
|
||||||
|
else:
|
||||||
|
record["accept"] += 1
|
||||||
|
#and see if it is spam tagged
|
||||||
|
if Isqueuedspam:
|
||||||
|
record["spam-tagged"] += 1
|
||||||
|
|
||||||
|
|
||||||
#Now increment the column which the plugin name indicates
|
#Now increment the column which the plugin name indicates
|
||||||
if parsed_data['action'] == '(deny)' and parsed_data['error-plugin']:
|
if parsed_data['action'] == '(deny)' and parsed_data['error-plugin']:
|
||||||
if parsed_data['error-plugin']:
|
if parsed_data['error-plugin']:
|
||||||
@ -1299,6 +1404,7 @@ if __name__ == "__main__":
|
|||||||
found_qpcodes[parsed_data['action1']] += 1
|
found_qpcodes[parsed_data['action1']] += 1
|
||||||
if isThonny:
|
if isThonny:
|
||||||
print() #seperate the [progress bar]
|
print() #seperate the [progress bar]
|
||||||
|
|
||||||
# Compute percentages
|
# Compute percentages
|
||||||
total_Count = columnCounts_2d[ColTotals][TOTALS]
|
total_Count = columnCounts_2d[ColTotals][TOTALS]
|
||||||
#Column of percentages
|
#Column of percentages
|
||||||
@ -1345,7 +1451,7 @@ if __name__ == "__main__":
|
|||||||
log_len = len(log_entries)
|
log_len = len(log_entries)
|
||||||
#connection_type_counts = defaultdict(int)
|
#connection_type_counts = defaultdict(int)
|
||||||
connection_type_counts = {"qpsmtp":total_qpsmtpd,"sqpsmtp":total_sqpsmtpd,"uqpsmtp":total_uqpsmtpd}
|
connection_type_counts = {"qpsmtp":total_qpsmtpd,"sqpsmtp":total_sqpsmtpd,"uqpsmtp":total_uqpsmtpd}
|
||||||
print(f"Con:{connection_type_counts}")
|
#print(f"Con:{connection_type_counts}")
|
||||||
if log_len > 0:
|
if log_len > 0:
|
||||||
if isThonny:
|
if isThonny:
|
||||||
print_progress_bar(0, log_len, prefix='Progress:', suffix='Complete', length=50)
|
print_progress_bar(0, log_len, prefix='Progress:', suffix='Complete', length=50)
|
||||||
@ -1452,19 +1558,44 @@ if __name__ == "__main__":
|
|||||||
#add in the subservient tables..
|
#add in the subservient tables..
|
||||||
|
|
||||||
#qpsmtd codes
|
#qpsmtd codes
|
||||||
|
#print(f"{found_qpcodes}")
|
||||||
qpsmtpd_headers = ["Reason",'Count','Percent']
|
qpsmtpd_headers = ["Reason",'Count','Percent']
|
||||||
qpsmtpd_title = 'Qpsmtpd codes league table:'
|
qpsmtpd_title = 'Qpsmtpd codes league table'
|
||||||
rendered_html = render_sub_table(qpsmtpd_title,qpsmtpd_headers,found_qpcodes)
|
rendered_html = render_sub_table(qpsmtpd_title,qpsmtpd_headers,found_qpcodes)
|
||||||
# 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 -->")
|
||||||
|
|
||||||
#Geoip Country codes
|
#Geoip Country codes
|
||||||
geoip_headers = ['Country','Count','Percent','Rejected?']
|
geoip_headers = ['Country','Count','Percent','Rejected?']
|
||||||
geoip_title = 'Geoip results:'
|
geoip_title = 'Geoip results'
|
||||||
rendered_html = render_sub_table(geoip_title,geoip_headers,found_countries,get_character_in_reject_list)
|
rendered_html = render_sub_table(geoip_title,geoip_headers,found_countries,get_character_in_reject_list)
|
||||||
# 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 -->")
|
||||||
|
|
||||||
|
#Junk mails
|
||||||
|
junk_mail_count_headers = ['Usernane','Count', 'Percent']
|
||||||
|
junk_mail_counts = scan_mail_users()
|
||||||
|
junk_mail_count_title = 'Junk mail counts'
|
||||||
|
rendered_html = render_sub_table(junk_mail_count_title,junk_mail_count_headers,junk_mail_counts)
|
||||||
|
# Add it to the total
|
||||||
|
total_html = insert_string_after(total_html,rendered_html, "<!---Add in sub tables here -->")
|
||||||
|
|
||||||
|
#virus codes
|
||||||
|
virus_headers = ["Virus",'Count','Percent']
|
||||||
|
virus_title = 'Virus types found'
|
||||||
|
rendered_html = render_sub_table(virus_title,virus_headers,found_viruses)
|
||||||
|
# Add it to the total
|
||||||
|
total_html = insert_string_after(total_html,rendered_html, "<!---Add in sub tables here -->")
|
||||||
|
|
||||||
|
#Recipient counts
|
||||||
|
#print(f"{recipients_found}")
|
||||||
|
recipient_count_headers = ["Email",'Queued','Rejected','Spam tagged','Accepted Percent']
|
||||||
|
recipient_count_title = 'Recipient count and status '
|
||||||
|
rendered_html = render_sub_table(recipient_count_title,recipient_count_headers,recipients_found)
|
||||||
|
# Add it to the total
|
||||||
|
total_html = insert_string_after(total_html,rendered_html, "<!---Add in sub tables here -->")
|
||||||
|
|
||||||
|
|
||||||
if saveData:
|
if saveData:
|
||||||
# Close the connection
|
# Close the connection
|
||||||
cursor.close()
|
cursor.close()
|
||||||
|
Loading…
Reference in New Issue
Block a user