From db5d631b0d10ede68366574c75deb6fbfcf876e5 Mon Sep 17 00:00:00 2001 From: Blake Ridgway Date: Tue, 18 Feb 2025 20:07:30 -0600 Subject: [PATCH] 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/ route for detailed view. * Developed new templates with navigation, including unsubscribe links. * Enhanced front-end styling and layout for newsletter pages. --- database.py | 10 ++++++ server.py | 39 ++++++++++++++++++++- static/css/styles.css | 58 ++++++++++++++++++++++++++++++-- templates/index.html | 7 ++-- templates/newsletter_detail.html | 35 +++++++++++++++++++ templates/newsletters.html | 43 +++++++++++++++++++++++ 6 files changed, 186 insertions(+), 6 deletions(-) create mode 100644 templates/newsletter_detail.html create mode 100644 templates/newsletters.html diff --git a/database.py b/database.py index 0ee6567..0569f18 100644 --- a/database.py +++ b/database.py @@ -25,6 +25,16 @@ def init_db(): email TEXT UNIQUE NOT NULL ) """) + + cursor.execute(""" + CREATE TABLE IF NOT EXISTS newsletters( + id SERIAL PRIMARY KEY, + subject TEXT NOT NULL, + body TEXT NOT NULL, + sent_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP + ) + """) + conn.commit() cursor.close() conn.close() diff --git a/server.py b/server.py index 2e2b4b8..eb94851 100644 --- a/server.py +++ b/server.py @@ -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/") +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) diff --git a/static/css/styles.css b/static/css/styles.css index c9dbdba..c644ca1 100644 --- a/static/css/styles.css +++ b/static/css/styles.css @@ -32,7 +32,7 @@ header nav a { text-decoration: none; color: #000; margin-left: 20px; - font-size: 18px; + font-size: 22px; } .hero-section-1 { @@ -179,15 +179,27 @@ main .inner-container { padding: 10px 20px; } - -footer { +.normal-footer { background-color: #337cf2; color: #fff; padding: 10px; text-align: center; clear: both; + margin-top: auto; } +.fixed-footer { + position: fixed; + bottom: 0; + left: 0; + width: 100%; + background-color: #337cf2; + color: #fff; + padding: 10px; + text-align: center; + z-index: 1000; + } + img { max-width: 100%; height: auto; @@ -253,3 +265,43 @@ img { padding: 50px 0; } } + +.newsletter { + margin-bottom: 40px; + border-bottom: 1px solid #ddd; + padding-bottom: 20px; +} + +.newsletter h2 { + color: #007bff; +} + +.newsletter-time { + color: #666; + font-size: 0.9em; + } + + .newsletter-detail { + max-width: 800px; + margin: 20px auto; + padding: 20px; + border: 1px solid #ddd; + border-radius: 8px; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); + } + .newsletter-detail h1 { + color: #007bff; + } + .newsletter-time { + color: #666; + font-size: 0.9em; + } + .back-link { + margin-top: 20px; + display: inline-block; + color: #007bff; + text-decoration: none; + } + .back-link:hover { + text-decoration: underline; + } \ No newline at end of file diff --git a/templates/index.html b/templates/index.html index 5fbbf34..0174394 100644 --- a/templates/index.html +++ b/templates/index.html @@ -9,7 +9,10 @@
@@ -84,7 +87,7 @@
-