feat(newsletter): add newsletters listing and detail pages

* Created a newsletters table and added insertion logic during newsletter send.
* Added a /newsletters route to display a list of sent newsletters.
* Implemented a /newsletter/<int:newsletter_id> route for detailed view.
* Developed new templates with navigation, including unsubscribe links.
* Enhanced front-end styling and layout for newsletter pages.
This commit is contained in:
Blake Ridgway 2025-02-18 20:07:30 -06:00
parent e3ae855a0b
commit db5d631b0d
6 changed files with 186 additions and 6 deletions

View file

@ -2,8 +2,9 @@ import os
import smtplib
from email.mime.text import MIMEText
from flask import Flask, render_template, request, jsonify
from database import init_db, add_email, remove_email
from database import get_connection, init_db, add_email, remove_email
from dotenv import load_dotenv
from collections import namedtuple
load_dotenv()
app = Flask(__name__)
@ -64,5 +65,41 @@ def unsubscribe():
else:
return f"Email {email} was not found or has already been unsubscribed.", 400
NewsItem = namedtuple('NewsItem', ['id', 'subject', 'body', 'sent_at'])
@app.route("/newsletters")
def newsletters():
conn = get_connection()
cursor = conn.cursor()
cursor.execute("SELECT id, subject, body, sent_at FROM newsletters ORDER BY sent_at DESC")
newsletter_records = cursor.fetchall()
cursor.close()
conn.close()
newsletters = [NewsItem(*rec) for rec in newsletter_records]
return render_template("newsletters.html", newsletters=newsletters)
@app.route("/newsletter/<int:newsletter_id>")
def newsletter_detail(newsletter_id):
conn = get_connection()
cursor = conn.cursor()
cursor.execute("SELECT id, subject, body, sent_at FROM newsletters WHERE id = %s", (newsletter_id,))
record = cursor.fetchone()
cursor.close()
conn.close()
if record is None:
return "Newsletter not found.", 404
newsletter = {
"id": record[0],
"subject": record[1],
"body": record[2],
"sent_at": record[3]
}
return render_template("newsletter_detail.html", newsletter=newsletter)
if __name__ == "__main__":
app.run(debug=True)