From 7ae9ef74785bbc03d169f8e11824e7b6d42cfcd7 Mon Sep 17 00:00:00 2001 From: Blake Ridgway Date: Wed, 12 Feb 2025 09:13:12 -0600 Subject: [PATCH] (feat): Initial work of admin panel --- .gitignore | 4 ++ .idea/.gitignore | 8 +++ .idea/admin-panel.iml | 21 ++++++ .../inspectionProfiles/profiles_settings.xml | 6 ++ .idea/misc.xml | 6 ++ .idea/modules.xml | 8 +++ Dockerfile | 12 ++++ app.py | 72 +++++++++++++++++++ requirements.txt | 2 + templates/admin_index.html | 33 +++++++++ templates/send_update.html | 37 ++++++++++ 11 files changed, 209 insertions(+) create mode 100644 .gitignore create mode 100644 .idea/.gitignore create mode 100644 .idea/admin-panel.iml create mode 100644 .idea/inspectionProfiles/profiles_settings.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/modules.xml create mode 100644 Dockerfile create mode 100644 app.py create mode 100644 requirements.txt create mode 100644 templates/admin_index.html create mode 100644 templates/send_update.html diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..bd9bc6c --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +/.venv/ +/.github/ +/__pycache__/ +/.env diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/admin-panel.iml b/.idea/admin-panel.iml new file mode 100644 index 0000000..27dc978 --- /dev/null +++ b/.idea/admin-panel.iml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000..105ce2d --- /dev/null +++ b/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..5b4eb67 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..18843a4 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..588c148 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,12 @@ +FROM python:3.11-slim + +WORKDIR /admin-panel + +COPY requirements.txt +RUN pip install --no-cache-dir -r requirements.txt + +COPY . . + +EXPOSE 5001 + +CMD ["python", "app.py"] \ No newline at end of file diff --git a/app.py b/app.py new file mode 100644 index 0000000..6f6ff6f --- /dev/null +++ b/app.py @@ -0,0 +1,72 @@ +import os +import sqlite3 +import smtplib +from email.mime.text import MIMEText +from flask import Flask, render_template, request, redirect, url_for, flash +from dotenv import load_dotenv + +load_dotenv() +app = Flask(__name__) + +app.secret_key = os.getenv('SECRET_KEY') + +DATABASE_URL = os.getenv('DATABASE_URL') +SMTP_SERVER = os.getenv('SMTP_SERVER') +SMTP_PORT = int(os.getenv("SMTP_PORT", 465)) +SMTP_USER = os.getenv('SMTP_USER') +SMTP_PASSWORD = os.getenv('SMTP_PASSWORD') + +def get_all_emails(): + """Retrieve all subscriber emails from the database""" + try: + conn = sqlite3.connect(DATABASE_URL) + cursor = conn.cursor() + cursor.execute('SELECT email FROM subscribers') + results = cursor.fetchall() + conn.close() + return [row[0] for row in results] + except Exception as e: + print(f"Error: {e}") + return [] + +def send_update_email(subject, body): + """Send an update email""" + subscribers = get_all_emails() + if not subscribers: + return "No subscribers found" + try: + server = smtplib.SMTP(SMTP_SERVER, SMTP_PORT, timeout=10) + server.set_debuglevel(True) + server.login(SMTP_USER, SMTP_PASSWORD) + for email in subscribers: + msg = MIMEText(body, 'html', 'utf-8') + msg['Subject'] = subject + msg['From'] = SMTP_USER + msg['To'] = email + server.sendmail(SMTP_USER, email, msg.as_string()) + print(f"Updated email for {email} has been sent.") + server.quit() + return "Email has been sent." + except Exception as e: + print(f"Failed to send email: {e}") + return f"Failed to send email: {e}" + +@app.route('/') +def index(): + """Displays all subscriber emails""" + emails = get_all_emails() + return render_template("admin_index.html", emails=emails) + +@app.route('/send_update_email', methods=['GET', 'POST']) +def send_update_email(): + """Display a form to send an update email""" + if request.method == 'POST': + subject = request.form['subject'] + body = request.form['body'] + result_message = send_update_email(subject, body) + flash(result_message) + return redirect(url_for("send_update_email")) + return render_template("send_update.html") + +if __name__ == '__main__': + app.run(port=5001, debug=True) diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..5a4a2b9 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +flask +python-dotenv \ No newline at end of file diff --git a/templates/admin_index.html b/templates/admin_index.html new file mode 100644 index 0000000..a03b4e3 --- /dev/null +++ b/templates/admin_index.html @@ -0,0 +1,33 @@ + + + + + + Admin Center - Subscribers + + + +

Subscribers

+

Send Update Email

+ {% if emails %} + + + + + {% for email in emails %} + + + + {% endfor %} +
Email Address
{{ email }}
+ {% else %} +

No subscribers found.

+ {% endif %} + + \ No newline at end of file diff --git a/templates/send_update.html b/templates/send_update.html new file mode 100644 index 0000000..e393bd0 --- /dev/null +++ b/templates/send_update.html @@ -0,0 +1,37 @@ + + + + + + Admin Center - Send Update + + + +

Send Update Email

+ {% with messages = get_flashed_messages() %} + {% if messages %} + {% for message in messages %} +
{{ message }}
+ {% endfor %} + {% endif %} + {% endwith %} + +
+ + + + + + + +
+

Back to Subscribers List

+ +