![]() |
|
const toggleUI = (busy) => btn.disabled = busy; spinner.classList.toggle('d-none', !busy); btnText.textContent = busy ? 'Downloading…' : 'Download PDF'; ;
<div id="downloadMsg" class="mt-3 text-muted"></div>
@bp.route("/download/gr-3108-core", methods=["GET"]) @login_required # <‑‑ remove/comment if public download is ok def download_gr_3108_core(): """ Serve GR‑3108‑Core.pdf. - Supports HTTP Range requests out‑of‑the‑box via Flask's `send_file`. - Logs every successful request (you can hook into any logger). """ filename = "GR-3108-Core.pdf" path = get_pdf_path(filename)
document.addEventListener('DOMContentLoaded', () => const btn = document.getElementById('downloadBtn'); const btnText = document.getElementById('btnText'); const spinner = document.getElementById('spinner'); const msgBox = document.getElementById('downloadMsg'); gr 3108 core pdf download
def get_pdf_path(filename: str) -> str: """ Return an absolute, safe path to the requested PDF. Raises 404 if the file does not exist. """ root = current_app.config["PDF_ROOT"] safe_path = safe_join(root, filename) if not safe_path or not os.path.isfile(safe_path): abort(404, description="PDF not found.") return safe_path
// Create a temporary <a> to trigger download const url = window.URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = filename; document.body.appendChild(a); a.click();
# Log (replace with proper logger) current_app.logger.info( f"User [request.remote_addr] downloading filename" ) const toggleUI = (busy) => btn
showMessage('✅ Download started.', 'success'); catch (err) console.error(err); showMessage(`❌ Failed: $err.message`, 'error'); finally toggleUI(false); ;
# OPTIONAL: clean‑up tasks after response is sent @after_this_request def add_custom_headers(r): # Example: custom analytics header r.headers["X-Download-Id"] = request.headers.get("X-Request-ID", "N/A") return r
// Stream the blob to avoid large memory spikes const blob = await response.blob(); - Logs every successful request (you can hook
const downloadFile = async () => toggleUI(true); showMessage('Preparing download…');
# Cache for a day – browsers can keep it locally max_age = current_app.config.get("PDF_MAX_AGE", 86400) expires = datetime.utcnow() + timedelta(seconds=max_age) response.headers["Cache-Control"] = f"public, max-age=max_age" response.headers["Expires"] = expires.strftime("%a, %d %b %Y %H:%M:%S GMT")
def create_app(): app = Flask(__name__) # ------------------------------ # App configuration (example) # ------------------------------ app.config.update( SECRET_KEY="replace‑with‑strong‑random‑bytes", PDF_ROOT="static/pdf", # folder where PDFs live PDF_MAX_AGE=86400, # 1 day browser cache ) # Register API blueprint app.register_blueprint(api_bp, url_prefix="/api/v1") return app import os from flask import current_app, abort, send_file, after_this_request from werkzeug.utils import safe_join from datetime import datetime, timedelta