Home > Software design >  How to push file for user download from third-party file
How to push file for user download from third-party file

Time:08-25

I am creating a function in my app that uses an API call to push dynamic HTML to convert it to a PDF. The API returns a download URL.

What I want to do, ideally without download back to my server and serving locally, is to have the file immediately start downloading. I was able to do this with send_file() with local files, but not with files stored elsewhere.

My code is:

@app.route('/generatereport', methods=['GET'])
@login_required
def generateReport():
    precords = people.find({"parentrecord": current_user.user_json['_id']}).sort('nextContact', pymongo.ASCENDING)
    todayDate = date.today()
    result = pdfgeneratorv2(info=precords, date=todayDate, user=current_user.user_json)

    return send_file(result, as_attachment=True)

and my pdfgeneratorv2 function is:

from jinja2 import Environment, select_autoescape, FileSystemLoader
from api2pdf import Api2Pdf
from dotenv import load_dotenv
import os

load_dotenv(dotenv_path='creds.env')

a2p_client = Api2Pdf(os.environ.get('Api2PdfKey'))


def pdfgeneratorv2(info, date, user):
    env = Environment(
        loader=FileSystemLoader('templates'),
        autoescape=select_autoescape(['html', 'xml'])
    )
    template = env.get_template('ReportTemplate.html')
    html = template.render(records=info, todayDate=date, user=user)
    api_response = a2p_client.Chrome.html_to_pdf(html, file_name='Networking Report.pdf')

    print(api_response.result)

    return api_response.result['FileUrl']

help would be greatly appreciated!

The error I get is:

Traceback (most recent call last):
  File "C:\Users\David PC\AppData\Local\Programs\Python\Python310\lib\site-packages\flask\app.py", line 2525, in wsgi_app
    response = self.full_dispatch_request()
  File "C:\Users\David PC\AppData\Local\Programs\Python\Python310\lib\site-packages\flask\app.py", line 1822, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "C:\Users\David PC\AppData\Local\Programs\Python\Python310\lib\site-packages\flask\app.py", line 1820, in full_dispatch_request
    rv = self.dispatch_request()
  File "C:\Users\David PC\AppData\Local\Programs\Python\Python310\lib\site-packages\flask\app.py", line 1796, in dispatch_request
    return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args)
  File "C:\Users\David PC\AppData\Local\Programs\Python\Python310\lib\site-packages\flask_login\utils.py", line 290, in decorated_view
    return current_app.ensure_sync(func)(*args, **kwargs)
  File "C:\Users\David PC\Desktop\VS Code Python\Flask Site\app.py", line 576, in generateReport
    return send_file(result, as_attachment=True)
  File "C:\Users\David PC\AppData\Local\Programs\Python\Python310\lib\site-packages\flask\helpers.py", line 537, in send_file
    return werkzeug.utils.send_file(  # type: ignore[return-value]
  File "C:\Users\David PC\AppData\Local\Programs\Python\Python310\lib\site-packages\werkzeug\utils.py", line 440, in send_file
    stat = os.stat(path)
OSError: [WinError 123] The filename, directory name, or volume label syntax is incorrect: 'C:\\Users\\David PC\\Desktop\\VS Code Python\\Flask Site\\https://URLREMOVED'

CodePudding user response:

Thank you to @OneCricketeer for pointing me in the right direction.

I ended up solving this using BytesIO.

My pdfgeneratorv2 function remained identical. My generateReport route was changed to:

@app.route('/generatereport', methods=['GET'])
@login_required
@limiter.limit("1/minute") # Maximum of 1 request per minute
def generateReport():
    precords = people.find({"parentrecord": current_user.user_json['_id']}).sort('nextContact', pymongo.ASCENDING)
    todayDate = date.today()
    result = pdfgeneratorv2(info=precords, date=todayDate, user=current_user.user_json)
    resp = requests.get(result)
    return send_file(BytesIO(resp.content), mimetype="application/pdf", download_name="Networking Report.pdf", as_attachment=True)

This also allows me to not have to delete the file afterwards.

  • Related