From 2f031591bfab3f4c3331395efd0ce5c675435463 Mon Sep 17 00:00:00 2001
From: RGalyaviev
Date: Thu, 4 Sep 2025 08:48:36 +0300
Subject: [PATCH] Export: add /p/.pdf and /p/.docx (xhtml2pdf +
htmldocx); overlay export buttons for all users; minor HTML wrapping
---
app.py | 58 ++++++++++++++++++++++++++++++++++++++++++++++--
requirements.txt | 3 +++
2 files changed, 59 insertions(+), 2 deletions(-)
diff --git a/app.py b/app.py
index bf8e73e..351ee2f 100644
--- a/app.py
+++ b/app.py
@@ -15,6 +15,10 @@ from flask import (
flash,
Response,
)
+from io import BytesIO
+from xhtml2pdf import pisa # type: ignore
+from docx import Document # type: ignore
+from htmldocx import HtmlToDocx # type: ignore
def create_app():
@@ -238,14 +242,64 @@ def create_app():
"Made by Ruslan"
""
)
+ # Export buttons (visible to everyone). If admin overlay exists, offset a bit.
+ top_offset = "60px" if is_logged_in() else "16px"
+ pdf_url = url_for("export_pdf", uid=uid)
+ docx_url = url_for("export_docx", uid=uid)
+ exports = (
+ f''
+ )
+ overlays = wm + exports
lower_all = html.lower()
if "
" +
+ html + "" in lower_all:
i2 = lower_all.rfind("")
- html = html[:i2] + wm + html[i2:]
+ html = html[:i2] + overlays + html[i2:]
else:
- html = html + wm
+ html = html + overlays
return Response(html, mimetype="text/html; charset=utf-8")
+ def _fetch_page(uid: str):
+ db = get_db()
+ row = db.execute("SELECT title, html FROM pages WHERE uuid = ?", (uid,)).fetchone()
+ if row is None:
+ abort(404)
+ return row
+
+ def _wrap_html_for_export(title: str, html: str) -> str:
+ head_title = f"
{title}" if title else ""
+ return (
+ "
" + head_title +
+ "