Remove deprecated PDF endpoint and update frontend download actions
Remove the old HTML-based PDF download endpoint in favor of the new WeasyPrint-based one, and replace the generic "Télécharger" button in popout.html with a dedicated .md download and a new PDF button. Also remove the unused generic download button from the main file view.
This commit is contained in:
parent
4929ff7beb
commit
dc9684e56c
@ -2816,51 +2816,6 @@ async def api_share_revoke(share_id: str, current_user=Depends(require_auth)):
|
|||||||
raise HTTPException(404, "Share not found")
|
raise HTTPException(404, "Share not found")
|
||||||
return {"status": "revoked"}
|
return {"status": "revoked"}
|
||||||
|
|
||||||
|
|
||||||
@app.get("/s/{token}/pdf")
|
|
||||||
async def public_share_pdf(token: str):
|
|
||||||
"""Download shared document as PDF — no authentication required."""
|
|
||||||
share = get_share_by_token(token)
|
|
||||||
if not share:
|
|
||||||
raise HTTPException(404, "Share not found or expired")
|
|
||||||
vault_data = get_vault_data(share["vault"])
|
|
||||||
if not vault_data:
|
|
||||||
raise HTTPException(404, "Vault not found")
|
|
||||||
vault_root = Path(vault_data["path"])
|
|
||||||
file_path = _resolve_safe_path(vault_root, share["path"])
|
|
||||||
if not file_path.exists():
|
|
||||||
raise HTTPException(404, "File not found")
|
|
||||||
try:
|
|
||||||
raw = file_path.read_text(encoding="utf-8", errors="replace")
|
|
||||||
except Exception:
|
|
||||||
raise HTTPException(500, "Cannot read file")
|
|
||||||
record_access(token)
|
|
||||||
raw = redact_file_content(raw, str(file_path))
|
|
||||||
post = parse_markdown_file(raw)
|
|
||||||
html = _render_markdown(post.content, share["vault"], file_path)
|
|
||||||
title = post.metadata.get("title", file_path.stem)
|
|
||||||
|
|
||||||
# Build a full HTML page for PDF rendering
|
|
||||||
full_html = f"""<!DOCTYPE html><html><head><meta charset="utf-8"><title>{title}</title>
|
|
||||||
<style>
|
|
||||||
body{{font-family:Georgia,serif;max-width:700px;margin:40px auto;padding:0 20px;line-height:1.7;color:#1a1a2e;font-size:13px}}
|
|
||||||
h1{{font-size:22px;border-bottom:2px solid #333;padding-bottom:6px}}h2{{font-size:18px;margin-top:20px}}h3{{font-size:15px}}
|
|
||||||
pre{{background:#f5f5f5;padding:10px;border-radius:4px;font-size:11px;overflow-x:auto}}code{{font-size:12px;background:#f5f5f5;padding:1px 3px}}
|
|
||||||
img{{max-width:100%}}blockquote{{border-left:3px solid #ccc;padding-left:12px;color:#555}}
|
|
||||||
table{{border-collapse:collapse;width:100%}}th,td{{border:1px solid #ddd;padding:6px 10px;text-align:left}}th{{background:#f0f0f0}}
|
|
||||||
</style></head><body><h1>{title}</h1>{html}</body></html>"""
|
|
||||||
|
|
||||||
filename = f"{title}.pdf"
|
|
||||||
return HTMLResponse(
|
|
||||||
content=full_html,
|
|
||||||
media_type="text/html",
|
|
||||||
headers={
|
|
||||||
"Content-Disposition": f'attachment; filename="{filename}"',
|
|
||||||
"X-PDF-Download": "true",
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@app.get("/s/{token}/pdf")
|
@app.get("/s/{token}/pdf")
|
||||||
async def public_share_pdf_download(token: str):
|
async def public_share_pdf_download(token: str):
|
||||||
"""Download shared document as real PDF via WeasyPrint."""
|
"""Download shared document as real PDF via WeasyPrint."""
|
||||||
|
|||||||
@ -3242,12 +3242,6 @@
|
|||||||
|
|
||||||
const sourceBtn = el("button", { class: "btn-action", title: "Voir la source" }, [icon("code", 14), document.createTextNode("Source")]);
|
const sourceBtn = el("button", { class: "btn-action", title: "Voir la source" }, [icon("code", 14), document.createTextNode("Source")]);
|
||||||
|
|
||||||
const downloadBtn = el("button", { class: "btn-action", title: "Télécharger" }, [icon("download", 14), document.createTextNode("Télécharger")]);
|
|
||||||
downloadBtn.addEventListener("click", () => {
|
|
||||||
const dlUrl = `/api/file/${encodeURIComponent(data.vault)}/download?path=${encodeURIComponent(data.path)}`;
|
|
||||||
window.open(dlUrl, "_blank");
|
|
||||||
});
|
|
||||||
|
|
||||||
// MD download button
|
// MD download button
|
||||||
const mdBtn = el("button", { class: "btn-action", title: "Télécharger en .md" }, [icon("file-text", 14), document.createTextNode(".md")]);
|
const mdBtn = el("button", { class: "btn-action", title: "Télécharger en .md" }, [icon("file-text", 14), document.createTextNode(".md")]);
|
||||||
mdBtn.addEventListener("click", () => {
|
mdBtn.addEventListener("click", () => {
|
||||||
@ -3359,7 +3353,7 @@
|
|||||||
// Assemble
|
// Assemble
|
||||||
area.innerHTML = "";
|
area.innerHTML = "";
|
||||||
area.appendChild(breadcrumb);
|
area.appendChild(breadcrumb);
|
||||||
area.appendChild(el("div", { class: "file-header" }, [el("div", { class: "file-title" }, [document.createTextNode(data.title)]), tagsDiv, el("div", { class: "file-actions" }, [copyBtn, sourceBtn, downloadBtn, mdBtn, pdfBtn, editBtn, openNewWindowBtn, tocBtn, shareBtn, bookmarkBtn])]));
|
area.appendChild(el("div", { class: "file-header" }, [el("div", { class: "file-title" }, [document.createTextNode(data.title)]), tagsDiv, el("div", { class: "file-actions" }, [copyBtn, sourceBtn, mdBtn, pdfBtn, editBtn, openNewWindowBtn, tocBtn, shareBtn, bookmarkBtn])]));
|
||||||
if (fmSection) area.appendChild(fmSection);
|
if (fmSection) area.appendChild(fmSection);
|
||||||
area.appendChild(mdDiv);
|
area.appendChild(mdDiv);
|
||||||
area.appendChild(rawDiv);
|
area.appendChild(rawDiv);
|
||||||
|
|||||||
@ -751,8 +751,8 @@ const RightSidebarManager = {
|
|||||||
|
|
||||||
const dlBtn = document.createElement("button");
|
const dlBtn = document.createElement("button");
|
||||||
dlBtn.className = "btn-action";
|
dlBtn.className = "btn-action";
|
||||||
dlBtn.title = "Télécharger";
|
dlBtn.title = "Télécharger en .md";
|
||||||
dlBtn.innerHTML = '<i data-lucide="download" style="width:14px;height:14px"></i> Télécharger';
|
dlBtn.innerHTML = '<i data-lucide="file-text" style="width:14px;height:14px"></i> .md';
|
||||||
dlBtn.addEventListener("click", () => {
|
dlBtn.addEventListener("click", () => {
|
||||||
const a = document.createElement("a");
|
const a = document.createElement("a");
|
||||||
a.href = `/api/file/${encodeURIComponent(vault)}/download?path=${encodeURIComponent(path)}`;
|
a.href = `/api/file/${encodeURIComponent(vault)}/download?path=${encodeURIComponent(path)}`;
|
||||||
@ -763,6 +763,15 @@ const RightSidebarManager = {
|
|||||||
});
|
});
|
||||||
actionsDiv.appendChild(dlBtn);
|
actionsDiv.appendChild(dlBtn);
|
||||||
|
|
||||||
|
const pdfBtn = document.createElement("button");
|
||||||
|
pdfBtn.className = "btn-action";
|
||||||
|
pdfBtn.title = "Télécharger en PDF";
|
||||||
|
pdfBtn.innerHTML = '<i data-lucide="file" style="width:14px;height:14px"></i> PDF';
|
||||||
|
pdfBtn.addEventListener("click", () => {
|
||||||
|
window.open(`/api/file/${encodeURIComponent(vault)}/pdf?path=${encodeURIComponent(path)}`, "_blank");
|
||||||
|
});
|
||||||
|
actionsDiv.appendChild(pdfBtn);
|
||||||
|
|
||||||
const editBtn = document.createElement("button");
|
const editBtn = document.createElement("button");
|
||||||
editBtn.className = "btn-action";
|
editBtn.className = "btn-action";
|
||||||
editBtn.title = "Éditer";
|
editBtn.title = "Éditer";
|
||||||
@ -779,6 +788,48 @@ const RightSidebarManager = {
|
|||||||
tocBtn.innerHTML = '<i data-lucide="list" style="width:14px;height:14px"></i> TOC';
|
tocBtn.innerHTML = '<i data-lucide="list" style="width:14px;height:14px"></i> TOC';
|
||||||
tocBtn.addEventListener("click", () => { RightSidebarManager.toggle(); });
|
tocBtn.addEventListener("click", () => { RightSidebarManager.toggle(); });
|
||||||
actionsDiv.appendChild(tocBtn);
|
actionsDiv.appendChild(tocBtn);
|
||||||
|
|
||||||
|
// Share button
|
||||||
|
const shareBtn = document.createElement("button");
|
||||||
|
shareBtn.className = "btn-action";
|
||||||
|
shareBtn.title = "Partager ce document";
|
||||||
|
shareBtn.innerHTML = '<i data-lucide="share-2" style="width:14px;height:14px"></i> Partager';
|
||||||
|
shareBtn.addEventListener("click", async () => {
|
||||||
|
try {
|
||||||
|
const res = await fetch(`/api/share/${encodeURIComponent(vault)}`, {
|
||||||
|
method: "POST",
|
||||||
|
headers: { "Content-Type": "application/json" },
|
||||||
|
body: JSON.stringify({ path }),
|
||||||
|
credentials: "include",
|
||||||
|
});
|
||||||
|
if (!res.ok) throw new Error("Erreur");
|
||||||
|
const share = await res.json();
|
||||||
|
const url = window.location.origin + share.url;
|
||||||
|
try { await navigator.clipboard.writeText(url); } catch { /* fallback */ }
|
||||||
|
alert("Lien copié : " + url);
|
||||||
|
} catch (err) { alert("Erreur: " + err.message); }
|
||||||
|
});
|
||||||
|
actionsDiv.appendChild(shareBtn);
|
||||||
|
|
||||||
|
// Bookmark button
|
||||||
|
const bookmarkBtn = document.createElement("button");
|
||||||
|
bookmarkBtn.className = "btn-action";
|
||||||
|
bookmarkBtn.title = "Ajouter/Retirer des bookmarks";
|
||||||
|
bookmarkBtn.innerHTML = '<i data-lucide="bookmark-plus" style="width:14px;height:14px"></i> Bookmark';
|
||||||
|
bookmarkBtn.addEventListener("click", async () => {
|
||||||
|
try {
|
||||||
|
const res = await fetch("/api/bookmarks/toggle", {
|
||||||
|
method: "POST",
|
||||||
|
headers: { "Content-Type": "application/json" },
|
||||||
|
body: JSON.stringify({ vault, path, title: data.title }),
|
||||||
|
credentials: "include",
|
||||||
|
});
|
||||||
|
if (!res.ok) throw new Error("Erreur");
|
||||||
|
const bm = await res.json();
|
||||||
|
bookmarkBtn.classList.toggle("active", bm.bookmarked);
|
||||||
|
} catch (err) { alert("Erreur: " + err.message); }
|
||||||
|
});
|
||||||
|
actionsDiv.appendChild(bookmarkBtn);
|
||||||
|
|
||||||
header.appendChild(actionsDiv);
|
header.appendChild(actionsDiv);
|
||||||
area.appendChild(header);
|
area.appendChild(header);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user