Untested, created email generation + styling

This commit is contained in:
Uthman Fatih 2025-10-13 20:41:45 +01:00
parent 80a354c484
commit fa8103051f

110
main.py
View File

@ -10,6 +10,8 @@ import time
import services.apt
import services.mail
from socket import gethostname
from dotenv import load_dotenv
from os import getenv
from os.path import dirname, join
@ -20,29 +22,117 @@ import typer
dotenv_path = join(dirname(__file__), ".env")
load_dotenv(dotenv_path)
# TODO: Logging
# TODO: Email alerts + structure
# TODO: Use typer for CLI
# TODO: Fix readme and git.uthmn.com page for final release.
# TODO: Error handling all round
# FIXME: Error handling
# FIXME: Add json email list that if not added will use parameters
# FIXME: Handle no updates available
app = typer.Typer()
@app.command()
def main():
def serve():
"""
Checks for updates and emails hourly for security, daily for general as a daemon.
"""
pass
@app.command()
def now():
def now(receiver_email: str):
"""
Checks for apt upgrades and emails them then exits.
"""
# TODO: Flag --now to run temporarily and just execute hourly tasks instantly then exit
pass
generate_email(receiver_email)
def generate_email(receiver_email: str):
services.apt.require_root()
if not services.apt.detect_apt():
print("Apt not found on this system.")
exit(1)
updates = services.apt.check_updates()
# Get how many security updates are available
security_updates = 0
for package in updates:
if package["security"]:
security_updates += 1
# Get how many total updates are available
total_updates = len(updates)
# Get how many general updates are available
general_updates = total_updates - security_updates
# Get system hostname
hostname = gethostname()
# Create email subject
subject = f"{hostname}> {security_updates} security updates, {general_updates} general updates available"
# Iterate over each security package and create a list of updates in html
security_chunks = ""
for package in updates:
if not package["security"]:
continue
chunk = f'''
<tr>
<td style="border: 1px solid #ddd; padding: 8px;">{package}</td>
<td style="border: 1px solid #ddd; padding: 8px;">{package["installed_version"]}</td>
<td style="border: 1px solid #ddd; padding: 8px;">{package["latest_version"]}</td>
<td style="border: 1px solid #ddd; padding: 8px;">{package["repo"]}</td>
</tr>
'''
security_chunks += chunk
security = f'''
<h1 style="font-family: Arial, sans-serif;">Security</h1>
<table style="border-collapse: collapse; width: 100%; font-family: Arial, sans-serif;">
<tr>
<th style="border: 1px solid #ddd; background-color: #f2f2f2; padding: 8px;">Package</th>
<th style="border: 1px solid #ddd; background-color: #f2f2f2; padding: 8px;">Installed</th>
<th style="border: 1px solid #ddd; background-color: #f2f2f2; padding: 8px;">Latest</th>
<th style="border: 1px solid #ddd; background-color: #f2f2f2; padding: 8px;">Repository</th>
</tr>
{security_chunks}
</table>
'''
# Iterate over each general package and create a list of updates in html
general_chunks = ""
for package in updates:
if package["security"]:
continue
chunk = f'''
<tr>
<td style="border: 1px solid #ddd; padding: 8px;">{package}</td>
<td style="border: 1px solid #ddd; padding: 8px;">{package["installed_version"]}</td>
<td style="border: 1px solid #ddd; padding: 8px;">{package["latest_version"]}</td>
<td style="border: 1px solid #ddd; padding: 8px;">{package["repo"]}</td>
</tr>
'''
general_chunks += chunk
general = f'''
<h1 style="font-family: Arial, sans-serif;">General</h1>
<table style="border-collapse: collapse; width: 100%; font-family: Arial, sans-serif;">
<tr>
<th style="border: 1px solid #ddd; background-color: #f2f2f2; padding: 8px;">Package</th>
<th style="border: 1px solid #ddd; background-color: #f2f2f2; padding: 8px;">Installed</th>
<th style="border: 1px solid #ddd; background-color: #f2f2f2; padding: 8px;">Latest</th>
<th style="border: 1px solid #ddd; background-color: #f2f2f2; padding: 8px;">Repository</th>
</tr>
{general_chunks}
</table>
'''
html += security
html += general
services.mail.send_email(receiver_email, subject, html)
@app.callback()
def callback():
"""