From dc9684e56c4e495d8d42888b998072ce67486420 Mon Sep 17 00:00:00 2001 From: Bruno Charest Date: Tue, 26 May 2026 21:55:42 -0400 Subject: [PATCH] Remove deprecated PDF endpoint and update frontend download actions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- backend/main.py | 45 ------------------------------------ frontend/app.js | 8 +------ frontend/popout.html | 55 ++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 54 insertions(+), 54 deletions(-) diff --git a/backend/main.py b/backend/main.py index 09cb54c..bbc0637 100644 --- a/backend/main.py +++ b/backend/main.py @@ -2816,51 +2816,6 @@ async def api_share_revoke(share_id: str, current_user=Depends(require_auth)): raise HTTPException(404, "Share not found") 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"""{title} -

{title}

{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") async def public_share_pdf_download(token: str): """Download shared document as real PDF via WeasyPrint.""" diff --git a/frontend/app.js b/frontend/app.js index 70b3601..2d02076 100644 --- a/frontend/app.js +++ b/frontend/app.js @@ -3242,12 +3242,6 @@ 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 const mdBtn = el("button", { class: "btn-action", title: "Télécharger en .md" }, [icon("file-text", 14), document.createTextNode(".md")]); mdBtn.addEventListener("click", () => { @@ -3359,7 +3353,7 @@ // Assemble area.innerHTML = ""; 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); area.appendChild(mdDiv); area.appendChild(rawDiv); diff --git a/frontend/popout.html b/frontend/popout.html index 8cdbf45..d23651b 100644 --- a/frontend/popout.html +++ b/frontend/popout.html @@ -751,8 +751,8 @@ const RightSidebarManager = { const dlBtn = document.createElement("button"); dlBtn.className = "btn-action"; - dlBtn.title = "Télécharger"; - dlBtn.innerHTML = ' Télécharger'; + dlBtn.title = "Télécharger en .md"; + dlBtn.innerHTML = ' .md'; dlBtn.addEventListener("click", () => { const a = document.createElement("a"); a.href = `/api/file/${encodeURIComponent(vault)}/download?path=${encodeURIComponent(path)}`; @@ -763,6 +763,15 @@ const RightSidebarManager = { }); actionsDiv.appendChild(dlBtn); + const pdfBtn = document.createElement("button"); + pdfBtn.className = "btn-action"; + pdfBtn.title = "Télécharger en PDF"; + pdfBtn.innerHTML = ' PDF'; + pdfBtn.addEventListener("click", () => { + window.open(`/api/file/${encodeURIComponent(vault)}/pdf?path=${encodeURIComponent(path)}`, "_blank"); + }); + actionsDiv.appendChild(pdfBtn); + const editBtn = document.createElement("button"); editBtn.className = "btn-action"; editBtn.title = "Éditer"; @@ -779,6 +788,48 @@ const RightSidebarManager = { tocBtn.innerHTML = ' TOC'; tocBtn.addEventListener("click", () => { RightSidebarManager.toggle(); }); actionsDiv.appendChild(tocBtn); + + // Share button + const shareBtn = document.createElement("button"); + shareBtn.className = "btn-action"; + shareBtn.title = "Partager ce document"; + shareBtn.innerHTML = ' 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 = ' 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); area.appendChild(header);