126 lines
3.5 KiB
Python
126 lines
3.5 KiB
Python
import os
|
|
import time
|
|
from datetime import datetime
|
|
|
|
import psycopg2
|
|
from flask import Flask, jsonify, request
|
|
|
|
app = Flask(__name__)
|
|
|
|
DB_CONFIG = {
|
|
"host": os.getenv("DB_HOST", "db"),
|
|
"port": int(os.getenv("DB_PORT", "5432")),
|
|
"dbname": os.getenv("DB_NAME", "guestbook"),
|
|
"user": os.getenv("DB_USER", "guestbook_user"),
|
|
"password": os.getenv("DB_PASSWORD", ""),
|
|
|
|
"sslmode": os.getenv("DB_SSLMODE", "prefer"),
|
|
}
|
|
|
|
APP_PORT = int(os.getenv("APP_PORT", "5000"))
|
|
|
|
|
|
def get_connection():
|
|
return psycopg2.connect(**DB_CONFIG)
|
|
|
|
|
|
def init_db(retries: int = 20, delay: int = 2) -> None:
|
|
for attempt in range(1, retries + 1):
|
|
try:
|
|
with get_connection() as conn:
|
|
with conn.cursor() as cur:
|
|
cur.execute(
|
|
"""
|
|
CREATE TABLE IF NOT EXISTS messages (
|
|
id SERIAL PRIMARY KEY,
|
|
author VARCHAR(100) NOT NULL,
|
|
content TEXT NOT NULL,
|
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
|
)
|
|
"""
|
|
)
|
|
conn.commit()
|
|
print("Database initialized.")
|
|
return
|
|
except Exception as exc:
|
|
print(f"Database not ready yet (attempt {attempt}/{retries}): {exc}")
|
|
time.sleep(delay)
|
|
raise RuntimeError("Could not initialize the database.")
|
|
|
|
|
|
@app.route("/api/health", methods=["GET"])
|
|
def health():
|
|
try:
|
|
with get_connection() as conn:
|
|
with conn.cursor() as cur:
|
|
cur.execute("SELECT 1")
|
|
cur.fetchone()
|
|
return jsonify({"status": "ok", "database": "connected"}), 200
|
|
except Exception as exc:
|
|
return jsonify({"status": "error", "database": str(exc)}), 500
|
|
|
|
|
|
@app.route("/api/messages", methods=["GET"])
|
|
def get_messages():
|
|
with get_connection() as conn:
|
|
with conn.cursor() as cur:
|
|
cur.execute(
|
|
"""
|
|
SELECT id, author, content, created_at
|
|
FROM messages
|
|
ORDER BY created_at DESC, id DESC
|
|
"""
|
|
)
|
|
rows = cur.fetchall()
|
|
|
|
data = [
|
|
{
|
|
"id": row[0],
|
|
"author": row[1],
|
|
"content": row[2],
|
|
"created_at": row[3].isoformat(),
|
|
}
|
|
for row in rows
|
|
]
|
|
return jsonify(data), 200
|
|
|
|
|
|
@app.route("/api/messages", methods=["POST"])
|
|
def add_message():
|
|
payload = request.get_json(silent=True) or {}
|
|
author = (payload.get("author") or "").strip()
|
|
content = (payload.get("content") or "").strip()
|
|
|
|
if not author or not content:
|
|
return jsonify({"error": "Fields 'author' and 'content' are required."}), 400
|
|
|
|
with get_connection() as conn:
|
|
with conn.cursor() as cur:
|
|
cur.execute(
|
|
"""
|
|
INSERT INTO messages (author, content, created_at)
|
|
VALUES (%s, %s, %s)
|
|
RETURNING id, author, content, created_at
|
|
""",
|
|
(author, content, datetime.utcnow()),
|
|
)
|
|
row = cur.fetchone()
|
|
conn.commit()
|
|
|
|
return (
|
|
jsonify(
|
|
{
|
|
"id": row[0],
|
|
"author": row[1],
|
|
"content": row[2],
|
|
"created_at": row[3].isoformat(),
|
|
}
|
|
),
|
|
201,
|
|
)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
init_db()
|
|
app.run(host="0.0.0.0", port=APP_PORT)
|