Files
quote-of-the-day/quotes.py
patrickbeane ddf5e983e2 Initial commit: Quote of the Day API
Secure, rate‑limited Flask + Gunicorn microservice with SQLite persistence, delivery tracking, and systemd deployment config. Includes setup script, HTML template, and production‑ready README.
2025-08-30 13:24:33 -04:00

65 lines
2.0 KiB
Python

from flask import Flask, jsonify, render_template
from flask_limiter import Limiter
from flask_limiter.util import get_remote_address
from werkzeug.middleware.proxy_fix import ProxyFix
import sqlite3
import random
import os
app = Flask(__name__)
app.wsgi_app = ProxyFix(app.wsgi_app, x_for=1, x_proto=1, x_host=1)
limiter = Limiter(key_func=get_remote_address, default_limits=["50/hour"])
limiter.init_app(app)
random.seed()
DB_FILE = "quotes.db"
def verify_db():
if not os.path.exists(DB_FILE):
raise RuntimeError("quotes.db not found. Run add-quotes.py to initialize.")
def get_random_quote():
"""Fetch a random quote from the database and increment delivered count"""
conn = sqlite3.connect(DB_FILE)
c = conn.cursor()
# Pick a random quote ID
c.execute("SELECT id, quote, author, delivered FROM quotes ORDER BY RANDOM() LIMIT 1")
row = c.fetchone()
if not row:
conn.close()
return None
quote_id, quote_text, author, delivered = row
# Increment delivered count atomically
c.execute("UPDATE quotes SET delivered = delivered + 1 WHERE id = ?", (quote_id,))
conn.commit()
conn.close()
return {"id": quote_id, "quote": quote_text, "author": author, "delivered": delivered + 1}
@app.route("/")
def main():
return render_template("quotes.html")
@app.route("/quote")
@limiter.limit("20/minute")
def quote():
quote = get_random_quote()
if not quote:
return "No quotes found in database!", 500
return f"{quote['quote']} - {quote['author']}"
@app.route("/api/quote")
@limiter.limit("50/minute")
def quote_api():
quote = get_random_quote()
if not quote:
return jsonify({"error": "No quotes found"}), 500
return jsonify(quote)
if __name__ == "__main__":
verify_db()
"""Running on Oracle's private network, in my instance - here it is 0.0.0.0 so only one node is needed"""
app.run(host="0.0.0.0", port=5051, debug=True)