Files
auto-publisher/analytics/collector.py

102 lines
2.9 KiB
Python

"""
Auto Publisher — Analytics collector endpoint.
Lightweight Flask app that runs on each site CT to collect pageview data.
"""
from flask import Flask, request, jsonify
import sqlite3
import json
import hashlib
import time
from datetime import datetime, timedelta
from pathlib import Path
app = Flask(__name__)
DB_PATH = "/var/lib/auto-publisher/analytics.db"
def get_db():
Path(DB_PATH).parent.mkdir(parents=True, exist_ok=True)
db = sqlite3.connect(DB_PATH)
db.execute("""
CREATE TABLE IF NOT EXISTS pageviews (
id INTEGER PRIMARY KEY AUTOINCREMENT,
path TEXT NOT NULL,
vertical TEXT NOT NULL,
referrer TEXT DEFAULT '',
user_agent TEXT DEFAULT '',
ip_hash TEXT DEFAULT '',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
""")
db.execute("""
CREATE INDEX IF NOT EXISTS idx_pageviews_path ON pageviews(path);
""")
db.execute("""
CREATE INDEX IF NOT EXISTS idx_pageviews_created ON pageviews(created_at);
""")
db.commit()
return db
@app.route("/a/collect", methods=["POST", "GET"])
def collect():
"""Collect a pageview ping."""
path = request.args.get("p", "/")
vertical = request.args.get("v", "unknown")
ref = request.args.get("r", "")
ua = request.headers.get("User-Agent", "")[:200]
ip = request.remote_addr or ""
ip_hash = hashlib.sha256(ip.encode()).hexdigest()[:16] if ip else ""
db = get_db()
db.execute(
"INSERT INTO pageviews (path, vertical, referrer, user_agent, ip_hash) VALUES (?, ?, ?, ?, ?)",
(path, vertical, ref, ua, ip_hash)
)
db.commit()
db.close()
# Return a 1x1 transparent GIF
return b"\x47\x49\x46\x38\x39\x61\x01\x00\x01\x00\x80\x00\x00\xff\xff\xff\x00\x00\x00\x21\xf9\x04\x01\x00\x00\x00\x00\x2c\x00\x00\x00\x00\x01\x00\x01\x00\x00\x02\x02\x44\x01\x00\x3b", 200, {
"Content-Type": "image/gif",
"Cache-Control": "no-cache, no-store, must-revalidate",
}
@app.route("/a/stats")
def stats():
"""Get site analytics summary."""
db = get_db()
db.row_factory = sqlite3.Row
today = datetime.now().strftime("%Y-%m-%d")
total = db.execute("SELECT COUNT(*) as c FROM pageviews").fetchone()["c"]
today_views = db.execute(
"SELECT COUNT(*) as c FROM pageviews WHERE created_at >= ?", (today,)
).fetchone()["c"]
top_pages = db.execute("""
SELECT path, COUNT(*) as c FROM pageviews
WHERE created_at >= date('now', '-30 days')
GROUP BY path ORDER BY c DESC LIMIT 10
""").fetchall()
db.close()
return jsonify({
"total_views": total,
"today_views": today_views,
"top_pages": [{"path": r["path"], "views": r["c"]} for r in top_pages],
})
@app.route("/health")
def health():
return jsonify({"status": "ok"})
if __name__ == "__main__":
app.run(host="0.0.0.0", port=5199, debug=False)