I need code to create a one-time download link for file uploaded using Flask. This link should be sent as email to the client. I have been able to create the dynamic link as per this solution:Link generator using django or any python module Modified part of the code(for flask):
def genUrl(filepath, fname): # create a onetime salt for randomness salt = ''.join(['{0}'.format(random.randrange(10) for i in range(10))]) key = hashlib.md5('{0}{1}'.format(salt, filepath)).hexdigest() s = select([msettings.c.DL_URL]) rs = conn.execute(s).fetchone() newpath = os.path.join(rs[msettings.c.DL_URL], key) shutil.copy2(filepath, newpath) ins = my_dlink.insert().values(key=key, download_date=datetime.datetime.utcnow(), orgpath=filepath, newpath=newpath ) rs1 = conn.execute(ins) print rs1.inserted_primary_key[0], 'inserted_primary_key' rs1.url = "{0}/{1}/{2}".format( rs[msettings.c.DL_URL], key, os.path.basename(fname)) return rs1.url @app.route('/archival/api/v1.0/archival_docs/<int:arc_file_id>/url', methods=['POST']) def generate_one_time_download_url_for_file(arc_file_id): path = '' s = select([archival_docs]).where(archival_docs.c.id == arc_file_id) rs = conn.execute(s).fetchone() if rs: path = os.path.join(("%s/%s" % (rs[archival_docs.c.path_map], rs[archival_docs.c.stored_name].encode('utf-8')))) new_link = genUrl(path, rs[archival_docs.c.stored_name]) # Use BytesIO instead of StringIO here. buffer = BytesIO() buffer.seek(0) content_type = mimetypes.guess_type(path)[0] print content_type, 'content_type' return send_file(buffer, as_attachment=True, attachment_filename=rs[archival_docs.c.stored_name], mimetype='text/plain')#content_type) # response = make_response(send_file(path)) # response.headers["Content-Disposition"] = \ # "attachment; " \ # "filename={ascii_filename};" \ # "filename*=UTF-8''{utf_filename}".format( # ascii_filename=rs[archival_docs.c.stored_name], # utf_filename=(os.path.basename(path)) # ) # print response #return response
How to send this as 1 time download link to client? After client downloads, this link should get disabled.i.e response should indicate that the file was downloaded(cron job should take care of it). What should be the exact code changes?
1 Answers
Answers 1
There is some information missing wrt performance, security etc and I am also unclear on what the cron job "should take care of", but from what I do understand, I have the impression you may be going about it the wrong way.
What I understand is that you want a "file" model with a status available (i.e. it was uploaded) or unavailable (i.e. it was already downloaded) and the following "pages":
- upload new file
- download file, with the following responses:
- a 404 if the file does not exist
- the file download if it was not downloaded yet
- a 'too late' message if it was already downloaded
Intermezzo on performance and security:
Typically, you want to bypass Flask to download static content and make the web server deal with this directly, but if you need to control file access + messages shown based on availability and download status of the file, it is easier to keep the same route and let Flask reply with the appropriate response.
Moreover, Flask has the send_file and send_from_directory functionality which does already quite some performance optimisation for you.
Nevertheless, it is possible to keep the file name + location + status seperate from the actual file and do a redirect to a static file download instead of using the Flask send_file functionality.
the "upload new file" function will for instance:
- accept the file
- create a new GUID
- store the file in a dedicated folder (include the GUID in the name, so two files with the same name don't overwrite each other)
- set initial state ("downloadable")
- send an email with a download link containing the GUID
- optional: store the file info in the db
the "download file" function will
- check the GUID parameter from the link
- check if the file exists / has existed
- "never heard of it" > 404 + send admin alert + ...
- "downloadable" > send file + change status + delete file + ...
- "already downloaded" > "too late" template + optionally increase counter + ...
I mention that the database is optional, because you could keep the downloadable files in one folder and move them to a "downloaded" folder when that happens and you can deduce the status of the different files from reading the folder contents, but I don't know what your constraints are or what else you may want to monitor.
Hope this helps you...
0 comments:
Post a Comment