diff --git a/.gitignore b/.gitignore index 3e8b3c5..f34a5ca 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ /.venv/ /.github/ /__pycache__/ -/.env \ No newline at end of file +/.env +venv 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..143f4d8 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,39 @@ def unsubscribe(): else: return f"Email {email} was not found or has already been unsubscribed.", 400 +@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") + results = cursor.fetchall() + newsletters = [ + {"id": rec[0], "subject": rec[1], "body": rec[2], "sent_at": rec[3]} + for rec in results + ] + cursor.close() + conn.close() + 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..a27334a 100644 --- a/static/css/styles.css +++ b/static/css/styles.css @@ -32,14 +32,14 @@ header nav a { text-decoration: none; color: #000; margin-left: 20px; - font-size: 18px; + font-size: 22px; } .hero-section-1 { width: 100%; margin: 0; padding: 0; - overflow: hidden; /* Hide any overflow if the image is larger */ + overflow: hidden; } .hero-content, .hero-text { @@ -50,10 +50,10 @@ header nav a { } .hero-text img { - width: 70%; /* The image will take up 50% of its container's width */ - height: auto; /* Maintain aspect ratio */ - display: block; /* Remove inline spacing if needed */ - margin: 0 auto; /* Center the image within its container if desired */ + width: 70%; + height: auto; + display: block; + margin: 0 auto; } .hero-text h1 { @@ -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,89 @@ 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; +} +.back-link { + margin-top: 20px; + display: inline-block; + color: #007bff; + text-decoration: none; +} +.back-link:hover { + text-decoration: underline; +} + +main h1 { + text-align: center; + margin-bottom: 20px; + color: #007bff; +} + +.cards-container { + display: flex; + flex-wrap: wrap; + justify-content: center; + gap: 20px; +} + +.newsletter-content { + width: 5000px%; +} + +.newsletter-card { + background: #fff; + border: 1px solid #ddd; + border-radius: 8px; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); + width: 300px; + display: flex; + flex-direction: column; + padding: 20px; + transition: transform 0.15s ease-in-out; +} + +.newsletter-card:hover { + transform: translateY(-5px); +} + +.newsletter-card h2 { + font-size: 1.5em; + color: #007bff; + margin-bottom: 10px; +} + +.newsletter-card p.newsletter-time { + font-size: 0.8em +} + +.newsletter-main { + max-width: 1200px; + margin: 0 auto; + padding: 20px; + } + 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 @@
-