如何使用Flask API将1次下载链接作为电子邮件发送?

时间:2016-05-30 11:55:05

标签: python flask

我需要代码为使用Flask上传的文件创建一次性下载链接。此链接应作为电子邮件发送给客户端。我已经能够根据此解决方案创建动态链接:Link generator using django or any python module 修改了部分代码(用于烧瓶):

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

如何将此作为1次下载链接发送给客户端?客户端下载后,此链接应该被禁用。响应应该指示文件已下载(cron作业应该处理它)。什么应该是确切的代码更改?

2 个答案:

答案 0 :(得分:1)

有一些信息遗漏了性能,安全性等,我也不清楚cron的工作应该“照顾”,但从我的理解,我的印象你可能会以错误的方式去做

我的理解是你想要一个状态可用(即上传)或不可用的“文件”模型(即已经下载) 和以下“页面”:

  • 上传新文件
  • 下载文件,包含以下回复:
    • 如果文件不存在,则为404
    • 文件下载(如果尚未下载)
    • 如果已经下载了“太迟”消息
  

关于性能和安全性的Intermezzo:

     

通常,您希望绕过Flask下载静态内容并使Web服务器直接处理此问题,但如果您需要根据文件的可用性和下载状态控制文件访问+消息,则更容易保留同样的路线让Flask回复相应的回复。

     

此外,Flask具有send_filesend_from_directory功能,可以为您提供相当多的性能优化。

     

尽管如此,可以将文件名+位置+状态与实际文件分开,并重定向到静态文件下载,而不是使用Flask send_file功能。

“上传新文件”功能将例如:

  • 接受文件
  • 创建新的GUID
  • 将文件存储在专用文件夹中(在名称中包含GUID,因此两个具有相同名称的文件不会相互覆盖)
  • 设置初始状态(“可下载”)
  • 发送包含GUID
  • 的下载链接的电子邮件
  • 可选:将文件信息存储在db

“下载文件”功能

  • 检查链接中的GUID参数
  • 检查文件是否存在
  • “从未听说过”&gt; 404 +发送管理员提醒+ ...
  • “可下载”&gt;发送文件+更改状态+删除文件+ ...
  • “已下载”&gt; “太迟了”模板+可选择增加计数器+ ...

我提到数据库是可选的,因为您可以将可下载文件保存在一个文件夹中并在发生这种情况时将它们移动到“已下载”文件夹,并且您可以从阅读文件夹内容中推断出不同文件的状态,但是我不知道你的约束是什么,或者你可能想要监控什么。

希望这可以帮助你...

答案 1 :(得分:-2)

的unlink($文件名); 这将删除该文件。

需要与ignore_user_abort()文档结合使用,即使用户取消下载,仍然会执行取消链接。

ignore_user_abort(真);

...

的unlink($ F);