import os import sqlite3 import uuid as uuid_lib from datetime import datetime from flask import ( Flask, g, render_template, request, redirect, url_for, session, abort, flash, Response, ) def create_app(): app = Flask(__name__) # Basic config app.config["SECRET_KEY"] = os.environ.get( "SECRET_KEY", # For production, override via env var. This default is for local/dev only. "dev-secret-change-me", ) app.config["DATABASE"] = os.path.join(os.path.dirname(__file__), "app.db") # Admin credentials (can be overridden via env) app.config["ADMIN_USERNAME"] = os.environ.get("ADMIN_USERNAME", "ruslan") app.config["ADMIN_PASSWORD"] = os.environ.get("ADMIN_PASSWORD", "utOgbZ09ruslan") # -------------------- # Database helpers # -------------------- def get_db(): if "db" not in g: g.db = sqlite3.connect(app.config["DATABASE"]) # type: ignore[attr-defined] g.db.row_factory = sqlite3.Row return g.db def close_db(e=None): db = g.pop("db", None) if db is not None: db.close() def init_db(): db = get_db() db.execute( """ CREATE TABLE IF NOT EXISTS pages ( id INTEGER PRIMARY KEY AUTOINCREMENT, uuid TEXT NOT NULL UNIQUE, title TEXT NOT NULL DEFAULT '', html TEXT NOT NULL, created_at TEXT NOT NULL ); """ ) # Migration: add 'title' column for older DB versions try: cols = {row[1] for row in db.execute("PRAGMA table_info(pages)").fetchall()} if "title" not in cols: db.execute("ALTER TABLE pages ADD COLUMN title TEXT NOT NULL DEFAULT ''") except Exception: pass db.commit() @app.before_request def _before_request(): # Ensure DB exists init_db() @app.teardown_appcontext def _teardown_appcontext(_=None): close_db() # -------------------- # Auth helpers # -------------------- def is_logged_in() -> bool: return bool(session.get("logged_in")) def login_required(): if not is_logged_in(): # For non-auth users: show nothing (404), not even an admin hint abort(404) @app.context_processor def inject_auth(): return {"logged_in": is_logged_in()} # -------------------- # Routes # -------------------- @app.route("/") def index(): # Redirect unauthenticated users to login; authenticated users to admin. if not is_logged_in(): return redirect(url_for("login")) return redirect(url_for("admin")) @app.route("/login", methods=["GET", "POST"]) def login(): if request.method == "POST": username = request.form.get("username", "") password = request.form.get("password", "") if ( username == app.config["ADMIN_USERNAME"] and password == app.config["ADMIN_PASSWORD"] ): session["logged_in"] = True flash("Успешный вход в админку.", "success") return redirect(url_for("admin")) flash("Неверные имя пользователя или пароль.", "error") return render_template("login.html") @app.route("/logout", methods=["POST"]) def logout(): session.clear() # After logout, nothing is visible. Return 404-like behavior. abort(404) @app.route("/admin", methods=["GET", "POST"]) def admin(): login_required() db = get_db() if request.method == "POST": title = request.form.get("title", "").strip() html = request.form.get("html", "").strip() if not html: flash("HTML не может быть пустым.", "error") else: uid = uuid_lib.uuid4().hex db.execute( "INSERT INTO pages (uuid, title, html, created_at) VALUES (?, ?, ?, ?)", (uid, title, html, datetime.utcnow().isoformat(timespec="seconds")), ) db.commit() flash("Страница опубликована.", "success") return redirect(url_for("admin")) pages = db.execute( "SELECT id, uuid, title, created_at FROM pages ORDER BY id DESC" ).fetchall() base_url = request.host_url.rstrip("/") return render_template("admin.html", pages=pages, base_url=base_url) @app.route("/admin/delete/", methods=["POST"]) def admin_delete(pid: int): login_required() db = get_db() cur = db.execute("DELETE FROM pages WHERE id = ?", (pid,)) db.commit() if cur.rowcount: flash("Страница удалена.", "success") else: flash("Страница не найдена.", "error") return redirect(url_for("admin")) @app.route("/p/") def view_page(uid: str): db = get_db() row = db.execute("SELECT html, title FROM pages WHERE uuid = ?", (uid,)).fetchone() if row is None: abort(404) # Show a floating admin button for authenticated users, otherwise serve raw HTML html: str = row["html"] # Inject tag for better page naming try: page_title = row["title"] except Exception: page_title = "" if page_title: lower = html.lower() if "</head>" in lower: i = lower.rfind("</head>") html = html[:i] + f"<title>{page_title}" + html[i:] elif "{page_title}" + html[j:] else: html = f"{page_title}" + html if is_logged_in(): admin_url = url_for("admin") toolbar = ( '
' f'Админка
' ) lower = html.lower() if "" in lower: idx = lower.rfind("") html = html[:idx] + toolbar + html[idx:] else: html = html + toolbar # Ensure watermark exists on published pages (top-left) wm = ( "" "" "" "
" "Made by Ruslan" "
" ) lower_all = html.lower() if "" in lower_all: i2 = lower_all.rfind("") html = html[:i2] + wm + html[i2:] else: html = html + wm return Response(html, mimetype="text/html; charset=utf-8") # Optional: simple 404 page to keep things minimal @app.errorhandler(404) def not_found(_): return ("", 404) return app app = create_app() if __name__ == "__main__": # Run development server app.run(host="0.0.0.0", port=int(os.environ.get("PORT", 5000)), debug=True)