first commit
This commit is contained in:
@@ -0,0 +1,468 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
flask_dropzone
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
:author: Grey Li <withlihui@gmail.com>
|
||||
:copyright: (c) 2017 by Grey Li.
|
||||
:license: MIT, see LICENSE for more details.
|
||||
"""
|
||||
import warnings
|
||||
from flask import Blueprint, current_app, url_for, Markup, render_template_string
|
||||
|
||||
from .utils import random_filename, get_url # noqa
|
||||
|
||||
#: defined normal file type
|
||||
allowed_file_extensions = {
|
||||
'default': 'image/*, audio/*, video/*, text/*, application/*',
|
||||
'image': 'image/*',
|
||||
'audio': 'audio/*',
|
||||
'video': 'video/*',
|
||||
'text': 'text/*',
|
||||
'app': 'application/*'
|
||||
}
|
||||
|
||||
|
||||
class _Dropzone(object):
|
||||
|
||||
@staticmethod
|
||||
def load(js_url='', css_url='', version='5.2.0'):
|
||||
"""Load Dropzone resources with given version and init dropzone configuration.
|
||||
|
||||
.. versionchanged:: 1.4.3
|
||||
Added ``js_url`` and ``css_url`` parameters to pass custom resource URL.
|
||||
|
||||
.. versionchanged:: 1.4.4
|
||||
This method was deprecated due to inflexible. Now it's divided into three methods:
|
||||
1. Use ``load_css()`` to load css resources.
|
||||
2. Use ``load_js()`` to load js resources.
|
||||
3. Use ``config()`` to configure Dropzone.
|
||||
|
||||
:param js_url: The JavaScript url for Dropzone.js.
|
||||
:param css_url: The CSS url for Dropzone.js.
|
||||
:param version: The version of Dropzone.js.
|
||||
"""
|
||||
warnings.warn('The method will be removed in 2.0, see docs for more details.')
|
||||
js_filename = 'dropzone.min.js'
|
||||
css_filename = 'dropzone.min.css'
|
||||
|
||||
upload_multiple = current_app.config['DROPZONE_UPLOAD_MULTIPLE']
|
||||
parallel_uploads = current_app.config['DROPZONE_PARALLEL_UPLOADS']
|
||||
|
||||
if upload_multiple in [True, 'true', 'True', 1]:
|
||||
upload_multiple = 'true'
|
||||
else:
|
||||
upload_multiple = 'false'
|
||||
|
||||
serve_local = current_app.config['DROPZONE_SERVE_LOCAL']
|
||||
size = current_app.config['DROPZONE_MAX_FILE_SIZE']
|
||||
param = current_app.config['DROPZONE_INPUT_NAME']
|
||||
redirect_view = current_app.config['DROPZONE_REDIRECT_VIEW']
|
||||
|
||||
if redirect_view is not None:
|
||||
redirect_js = '''
|
||||
this.on("queuecomplete", function(file) {
|
||||
// Called when all files in the queue finish uploading.
|
||||
window.location = "%s";
|
||||
});''' % url_for(redirect_view)
|
||||
else:
|
||||
redirect_js = ''
|
||||
|
||||
if not current_app.config['DROPZONE_ALLOWED_FILE_CUSTOM']:
|
||||
allowed_type = allowed_file_extensions[
|
||||
current_app.config['DROPZONE_ALLOWED_FILE_TYPE']]
|
||||
else:
|
||||
allowed_type = current_app.config['DROPZONE_ALLOWED_FILE_TYPE']
|
||||
|
||||
max_files = current_app.config['DROPZONE_MAX_FILES']
|
||||
default_message = current_app.config['DROPZONE_DEFAULT_MESSAGE']
|
||||
invalid_file_type = current_app.config['DROPZONE_INVALID_FILE_TYPE']
|
||||
file_too_big = current_app.config['DROPZONE_FILE_TOO_BIG']
|
||||
server_error = current_app.config['DROPZONE_SERVER_ERROR']
|
||||
browser_unsupported = current_app.config['DROPZONE_BROWSER_UNSUPPORTED']
|
||||
max_files_exceeded = current_app.config['DROPZONE_MAX_FILE_EXCEED']
|
||||
cancelUpload = current_app.config['DROPZONE_CANCEL_UPLOAD']
|
||||
removeFile = current_app.config['DROPZONE_REMOVE_FILE']
|
||||
cancelConfirmation = current_app.config['DROPZONE_CANCEL_CONFIRMATION']
|
||||
uploadCanceled = current_app.config['DROPZONE_UPLOAD_CANCELED']
|
||||
|
||||
timeout = current_app.config['DROPZONE_TIMEOUT']
|
||||
if timeout:
|
||||
timeout_js = 'timeout: %d,' % timeout
|
||||
else:
|
||||
timeout_js = ''
|
||||
|
||||
if serve_local:
|
||||
js = '<script src="%s"></script>\n' % url_for('dropzone.static', filename=js_filename)
|
||||
css = '<link rel="stylesheet" href="%s" type="text/css">\n' % \
|
||||
url_for('dropzone.static', filename=css_filename)
|
||||
else:
|
||||
js = '<script src="https://cdn.jsdelivr.net/npm/dropzone@%s/dist/%s"></script>\n' % (version, js_filename)
|
||||
css = '<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/dropzone@%s/dist/min/%s"' \
|
||||
' type="text/css">\n' % (version, css_filename)
|
||||
|
||||
if js_url:
|
||||
js = '<script src="%s"></script>\n' % js_url
|
||||
if css_url:
|
||||
css = '<link rel="stylesheet" href="%s" type="text/css">\n' % css_url
|
||||
|
||||
return Markup('''
|
||||
%s%s<script>
|
||||
Dropzone.options.myDropzone = {
|
||||
init: function() {%s},
|
||||
uploadMultiple: %s,
|
||||
parallelUploads: %d,
|
||||
paramName: "%s", // The name that will be used to transfer the file
|
||||
maxFilesize: %d, // MB
|
||||
acceptedFiles: "%s",
|
||||
maxFiles: %s,
|
||||
dictDefaultMessage: "%s", // message display on drop area
|
||||
dictFallbackMessage: "%s",
|
||||
dictInvalidFileType: "%s",
|
||||
dictFileTooBig: "%s",
|
||||
dictResponseError: "%s",
|
||||
dictMaxFilesExceeded: "%s",
|
||||
dictCancelUpload: "%s",
|
||||
dictRemoveFile: "%s",
|
||||
dictCancelUploadConfirmation: "%s",
|
||||
dictUploadCanceled: "%s",
|
||||
%s // timeout
|
||||
};
|
||||
</script>
|
||||
''' % (css, js, redirect_js, upload_multiple, parallel_uploads, param, size, allowed_type, max_files,
|
||||
default_message, browser_unsupported, invalid_file_type, file_too_big, server_error,
|
||||
max_files_exceeded, cancelUpload, removeFile, cancelConfirmation, uploadCanceled, timeout_js))
|
||||
|
||||
@staticmethod
|
||||
def load_css(css_url=None, version='5.2.0'):
|
||||
"""Load Dropzone's css resources with given version.
|
||||
|
||||
.. versionadded:: 1.4.4
|
||||
|
||||
:param css_url: The CSS url for Dropzone.js.
|
||||
:param version: The version of Dropzone.js.
|
||||
"""
|
||||
css_filename = 'dropzone.min.css'
|
||||
serve_local = current_app.config['DROPZONE_SERVE_LOCAL']
|
||||
|
||||
if serve_local:
|
||||
css = '<link rel="stylesheet" href="%s" type="text/css">\n' % \
|
||||
url_for('dropzone.static', filename=css_filename)
|
||||
else:
|
||||
css = '<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/dropzone@%s/dist/min/%s"' \
|
||||
' type="text/css">\n' % (version, css_filename)
|
||||
|
||||
if css_url:
|
||||
css = '<link rel="stylesheet" href="%s" type="text/css">\n' % css_url
|
||||
return Markup(css)
|
||||
|
||||
@staticmethod
|
||||
def load_js(js_url=None, version='5.2.0'):
|
||||
"""Load Dropzone's js resources with given version.
|
||||
|
||||
.. versionadded:: 1.4.4
|
||||
|
||||
:param js_url: The JS url for Dropzone.js.
|
||||
:param version: The version of Dropzone.js.
|
||||
"""
|
||||
js_filename = 'dropzone.min.js'
|
||||
serve_local = current_app.config['DROPZONE_SERVE_LOCAL']
|
||||
|
||||
if serve_local:
|
||||
js = '<script src="%s"></script>\n' % url_for('dropzone.static', filename=js_filename)
|
||||
else:
|
||||
js = '<script src="https://cdn.jsdelivr.net/npm/dropzone@%s/dist/%s"></script>\n' % (version, js_filename)
|
||||
|
||||
if js_url:
|
||||
js = '<script src="%s"></script>\n' % js_url
|
||||
return Markup(js)
|
||||
|
||||
@staticmethod
|
||||
def config(redirect_url=None, custom_init='', custom_options='', nonce=None, id=None, **kwargs):
|
||||
"""Initialize dropzone configuration.
|
||||
|
||||
.. versionchanged:: 1.5.4
|
||||
Added ``id`` parameter.
|
||||
|
||||
.. versionadded:: 1.4.4
|
||||
|
||||
:param redirect_url: The URL to redirect when upload complete.
|
||||
:param custom_init: Custom javascript code in ``init: function() {}``.
|
||||
:param custom_options: Custom javascript code in ``Dropzone.options.myDropzone = {}``.
|
||||
:param nonce: Pass a nonce value that is newhen embedding the JavaScript code into a Content Security Policy protected web page.
|
||||
:param id: The id of the dropzone element, it must matches the ``id`` argument passed to
|
||||
``dropzone.create()`` if provided.
|
||||
:param **kwargs: Mirror configuration variable, lowercase and without prefix.
|
||||
For example, ``DROPZONE_UPLOAD_MULTIPLE`` becomes ``upload_multiple`` here.
|
||||
"""
|
||||
if custom_init and not custom_init.strip().endswith(';'):
|
||||
custom_init += ';'
|
||||
|
||||
if custom_options and not custom_options.strip().endswith(','):
|
||||
custom_options += ','
|
||||
|
||||
upload_multiple = kwargs.get('upload_multiple', current_app.config['DROPZONE_UPLOAD_MULTIPLE'])
|
||||
parallel_uploads = kwargs.get('parallel_uploads', current_app.config['DROPZONE_PARALLEL_UPLOADS'])
|
||||
|
||||
if upload_multiple in [True, 'true', 'True', 1]:
|
||||
upload_multiple = 'true'
|
||||
else:
|
||||
upload_multiple = 'false'
|
||||
|
||||
size = kwargs.get('max_file_size', current_app.config['DROPZONE_MAX_FILE_SIZE'])
|
||||
param = kwargs.get('input_name', current_app.config['DROPZONE_INPUT_NAME'])
|
||||
redirect_view = kwargs.get('redirect_view', current_app.config['DROPZONE_REDIRECT_VIEW'])
|
||||
|
||||
if redirect_view is not None or redirect_url is not None:
|
||||
redirect_url = redirect_url or url_for(redirect_view)
|
||||
redirect_js = '''
|
||||
this.on("queuecomplete", function(file) {
|
||||
// Called when all files in the queue finish uploading.
|
||||
window.location = "%s";
|
||||
});''' % redirect_url
|
||||
else:
|
||||
redirect_js = ''
|
||||
|
||||
max_files = kwargs.get('max_files', current_app.config['DROPZONE_MAX_FILES'])
|
||||
|
||||
click_upload = kwargs.get('upload_on_click', current_app.config['DROPZONE_UPLOAD_ON_CLICK'])
|
||||
button_id = kwargs.get('upload_btn_id', current_app.config['DROPZONE_UPLOAD_BTN_ID'])
|
||||
in_form = kwargs.get('in_form', current_app.config['DROPZONE_IN_FORM'])
|
||||
cancelUpload = kwargs.get('cancel_upload', current_app.config['DROPZONE_CANCEL_UPLOAD'])
|
||||
removeFile = kwargs.get('remove_file', current_app.config['DROPZONE_REMOVE_FILE'])
|
||||
cancelConfirmation = kwargs.get('cancel_confirmation', current_app.config['DROPZONE_CANCEL_CONFIRMATION'])
|
||||
uploadCanceled = kwargs.get('upload_canceled', current_app.config['DROPZONE_UPLOAD_CANCELED'])
|
||||
|
||||
if click_upload:
|
||||
if in_form:
|
||||
action = get_url(kwargs.get('upload_action', current_app.config['DROPZONE_UPLOAD_ACTION']))
|
||||
|
||||
click_listener = '''
|
||||
dz = this; // Makes sure that 'this' is understood inside the functions below.
|
||||
|
||||
document.getElementById("%s").addEventListener("click", function handler(e) {
|
||||
e.currentTarget.removeEventListener(e.type, handler);
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
dz.processQueue();
|
||||
});
|
||||
this.on("queuecomplete", function(file) {
|
||||
// Called when all files in the queue finish uploading.
|
||||
document.getElementById("%s").click();
|
||||
});
|
||||
''' % (button_id, button_id)
|
||||
click_option = '''
|
||||
url: "%s",
|
||||
autoProcessQueue: false,
|
||||
// addRemoveLinks: true,
|
||||
''' % action
|
||||
else:
|
||||
click_listener = '''
|
||||
dz = this;
|
||||
document.getElementById("%s").addEventListener("click", function handler(e) {dz.processQueue();});
|
||||
''' % button_id
|
||||
|
||||
click_option = '''
|
||||
autoProcessQueue: false,
|
||||
// addRemoveLinks: true,
|
||||
'''
|
||||
upload_multiple = 'true'
|
||||
parallel_uploads = max_files if isinstance(max_files, int) else parallel_uploads
|
||||
else:
|
||||
click_listener = ''
|
||||
click_option = ''
|
||||
|
||||
allowed_file_type = kwargs.get('allowed_file_type', current_app.config['DROPZONE_ALLOWED_FILE_TYPE'])
|
||||
allowed_file_custom = kwargs.get('allowed_file_custom', current_app.config['DROPZONE_ALLOWED_FILE_CUSTOM'])
|
||||
|
||||
if allowed_file_custom:
|
||||
allowed_type = allowed_file_type
|
||||
else:
|
||||
allowed_type = allowed_file_extensions[allowed_file_type]
|
||||
|
||||
default_message = kwargs.get('default_message', current_app.config['DROPZONE_DEFAULT_MESSAGE'])
|
||||
invalid_file_type = kwargs.get('invalid_file_type', current_app.config['DROPZONE_INVALID_FILE_TYPE'])
|
||||
file_too_big = kwargs.get('file_too_big', current_app.config['DROPZONE_FILE_TOO_BIG'])
|
||||
server_error = kwargs.get('server_error', current_app.config['DROPZONE_SERVER_ERROR'])
|
||||
browser_unsupported = kwargs.get('browser_unsupported', current_app.config['DROPZONE_BROWSER_UNSUPPORTED'])
|
||||
max_files_exceeded = kwargs.get('max_file_exceeded', current_app.config['DROPZONE_MAX_FILE_EXCEED'])
|
||||
|
||||
timeout = kwargs.get('timeout', current_app.config['DROPZONE_TIMEOUT'])
|
||||
if timeout:
|
||||
custom_options += 'timeout: %d,' % timeout
|
||||
|
||||
enable_csrf = kwargs.get('enable_csrf', current_app.config['DROPZONE_ENABLE_CSRF'])
|
||||
if enable_csrf:
|
||||
if 'csrf' not in current_app.extensions:
|
||||
raise RuntimeError("CSRFProtect is not initialized. It's required to enable CSRF protect, \
|
||||
see docs for more details.")
|
||||
csrf_token = render_template_string('{{ csrf_token() }}')
|
||||
custom_options += 'headers: {"X-CSRF-Token": "%s"},' % csrf_token
|
||||
|
||||
nonce_html = ' nonce="%s"' % nonce if nonce else ''
|
||||
if id is None:
|
||||
id = 'myDropzone'
|
||||
|
||||
return Markup('''<script%s>
|
||||
Dropzone.options.%s = {
|
||||
init: function() {
|
||||
%s // redirect after queue complete
|
||||
%s // upload queue when button click
|
||||
%s // custom init code
|
||||
},
|
||||
%s // click upload options
|
||||
uploadMultiple: %s,
|
||||
parallelUploads: %d,
|
||||
paramName: "%s", // The name that will be used to transfer the file
|
||||
maxFilesize: %d, // MB
|
||||
acceptedFiles: "%s",
|
||||
maxFiles: %s,
|
||||
dictDefaultMessage: `%s`, // message display on drop area
|
||||
dictFallbackMessage: "%s",
|
||||
dictInvalidFileType: "%s",
|
||||
dictFileTooBig: "%s",
|
||||
dictResponseError: "%s",
|
||||
dictMaxFilesExceeded: "%s",
|
||||
dictCancelUpload: "%s",
|
||||
dictRemoveFile: "%s",
|
||||
dictCancelUploadConfirmation: "%s",
|
||||
dictUploadCanceled: "%s",
|
||||
%s // custom options code
|
||||
};
|
||||
</script>
|
||||
''' % (nonce_html, id, redirect_js, click_listener, custom_init, click_option,
|
||||
upload_multiple, parallel_uploads, param, size, allowed_type, max_files,
|
||||
default_message, browser_unsupported, invalid_file_type, file_too_big,
|
||||
server_error, max_files_exceeded, cancelUpload, removeFile, cancelConfirmation,
|
||||
uploadCanceled, custom_options))
|
||||
|
||||
@staticmethod
|
||||
def create(action='', csrf=False, action_view='', id=None, **kwargs):
|
||||
"""Create a Dropzone form with given action.
|
||||
|
||||
.. versionchanged:: 1.4.2
|
||||
Added ``csrf`` parameter to enable CSRF protect.
|
||||
|
||||
.. versionchanged:: 1.4.3
|
||||
Added ``action`` parameter to replace ``action_view``, ``action_view`` was deprecated now.
|
||||
|
||||
.. versionchanged:: 1.5.0
|
||||
If ``DROPZONE_IN_FORM`` set to ``True``, create ``<div>`` instead of ``<form>``.
|
||||
|
||||
.. versionchanged:: 1.5.4
|
||||
``csrf`` was deprecated now.
|
||||
|
||||
.. versionchanged:: 1.5.4
|
||||
Added ``id`` parameter.
|
||||
|
||||
:param action: The action attribute in ``<form>``, pass the url which handle uploads.
|
||||
:param csrf: Enable CSRF protect or not, same with ``DROPZONE_ENABLE_CSRF``, deprecated since 1.5.4.
|
||||
:param action_view: The view which handle the post data, deprecated since 1.4.2.
|
||||
:param id: The id of the dropzone element, it must matches the ``id`` argument passed to
|
||||
``dropzone.config()`` if provided.
|
||||
"""
|
||||
if current_app.config['DROPZONE_IN_FORM']:
|
||||
return Markup('<div class="dropzone" id="myDropzone"></div>')
|
||||
|
||||
if action:
|
||||
action_url = get_url(action, **kwargs)
|
||||
else:
|
||||
warnings.warn('The argument was renamed to "action" and will be removed in 2.0.')
|
||||
action_url = url_for(action_view, **kwargs)
|
||||
|
||||
if csrf:
|
||||
warnings.warn('The argument was deprecated and will be removed in 2.0, use DROPZONE_ENABLE_CSRF instead.')
|
||||
|
||||
if id is None:
|
||||
id = 'myDropzone'
|
||||
return Markup('''<form action="%s" method="post" class="dropzone" id="%s"
|
||||
enctype="multipart/form-data"></form>''' % (action_url, id))
|
||||
|
||||
@staticmethod
|
||||
def style(css):
|
||||
"""Add css to dropzone.
|
||||
|
||||
:param css: style sheet code.
|
||||
"""
|
||||
return Markup('<style>\n.dropzone{%s}\n</style>' % css)
|
||||
|
||||
|
||||
class Dropzone(object):
|
||||
def __init__(self, app=None):
|
||||
if app is not None:
|
||||
self.init_app(app)
|
||||
|
||||
def init_app(self, app):
|
||||
|
||||
blueprint = Blueprint('dropzone', __name__,
|
||||
static_folder='static',
|
||||
static_url_path='/dropzone' + app.static_url_path)
|
||||
app.register_blueprint(blueprint)
|
||||
|
||||
if not hasattr(app, 'extensions'):
|
||||
app.extensions = {}
|
||||
app.extensions['dropzone'] = _Dropzone
|
||||
app.context_processor(self.context_processor)
|
||||
|
||||
# settings
|
||||
app.config.setdefault('DROPZONE_SERVE_LOCAL', False)
|
||||
app.config.setdefault('DROPZONE_MAX_FILE_SIZE', 3) # MB
|
||||
app.config.setdefault('DROPZONE_INPUT_NAME', 'file')
|
||||
app.config.setdefault('DROPZONE_ALLOWED_FILE_CUSTOM', False)
|
||||
app.config.setdefault('DROPZONE_ALLOWED_FILE_TYPE', 'default')
|
||||
app.config.setdefault('DROPZONE_MAX_FILES', 'null')
|
||||
# The timeout to cancel upload request in millisecond, default to 30000 (30 second).
|
||||
# Set a large number if you need to upload large file.
|
||||
# .. versionadded: 1.5.0
|
||||
app.config.setdefault('DROPZONE_TIMEOUT', None) # millisecond, default to 30000 (30 second)
|
||||
|
||||
# The view to redirect when upload was completed.
|
||||
# .. versionadded:: 1.4.1
|
||||
app.config.setdefault('DROPZONE_REDIRECT_VIEW', None)
|
||||
|
||||
# Whether to send multiple files in one request.
|
||||
# In default, each file will send with a request.
|
||||
# Then you can use ``request.files.getlist('paramName')`` to
|
||||
# get a list of uploads.
|
||||
# .. versionadded:: 1.4.1
|
||||
app.config.setdefault('DROPZONE_UPLOAD_MULTIPLE', False)
|
||||
|
||||
# When ``DROPZONE_UPLOAD_MULTIPLE`` set to True, this will
|
||||
# defined how many uploads will handled in per request.
|
||||
# .. versionadded:: 1.4.1
|
||||
app.config.setdefault('DROPZONE_PARALLEL_UPLOADS', 2)
|
||||
|
||||
# When set to ``True``, it will add a csrf_token hidden field in upload form.
|
||||
# You have to install Flask-WTF to make it work properly, see details in docs.
|
||||
# .. versionadded:: 1.4.2
|
||||
app.config.setdefault('DROPZONE_ENABLE_CSRF', False)
|
||||
|
||||
# Add support to upload files when button was clicked.
|
||||
# .. versionadded:: 1.5.0
|
||||
app.config.setdefault('DROPZONE_UPLOAD_ACTION', '')
|
||||
app.config.setdefault('DROPZONE_UPLOAD_ON_CLICK', False)
|
||||
app.config.setdefault('DROPZONE_UPLOAD_BTN_ID', 'upload')
|
||||
|
||||
# Add support to create dropzone inside ``<form>``.
|
||||
# .. versionadded:: 1.5.0
|
||||
app.config.setdefault('DROPZONE_IN_FORM', False)
|
||||
|
||||
# messages
|
||||
app.config.setdefault('DROPZONE_DEFAULT_MESSAGE', "Drop files here or click to upload.")
|
||||
app.config.setdefault('DROPZONE_INVALID_FILE_TYPE', "You can't upload files of this type.")
|
||||
app.config.setdefault('DROPZONE_FILE_TOO_BIG',
|
||||
"File is too big {{filesize}}. Max filesize: {{maxFilesize}}MiB.")
|
||||
app.config.setdefault('DROPZONE_SERVER_ERROR', "Server error: {{statusCode}}")
|
||||
app.config.setdefault('DROPZONE_BROWSER_UNSUPPORTED',
|
||||
"Your browser does not support drag'n'drop file uploads.")
|
||||
app.config.setdefault('DROPZONE_MAX_FILE_EXCEED', "You can't upload any more files.")
|
||||
app.config.setdefault('DROPZONE_CANCEL_UPLOAD', "Cancel upload")
|
||||
app.config.setdefault('DROPZONE_REMOVE_FILE', "Remove file")
|
||||
app.config.setdefault('DROPZONE_CANCEL_CONFIRMATION', "You really want to delete this file?")
|
||||
app.config.setdefault('DROPZONE_UPLOAD_CANCELED', "Upload canceled")
|
||||
|
||||
@staticmethod
|
||||
def context_processor():
|
||||
return {
|
||||
'dropzone': current_app.extensions['dropzone']
|
||||
}
|
||||
BIN
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,28 @@
|
||||
"""
|
||||
flask_dropzone.utils
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
:author: Grey Li <withlihui@gmail.com>
|
||||
:copyright: (c) 2017 by Grey Li.
|
||||
:license: MIT, see LICENSE for more details.
|
||||
"""
|
||||
import os
|
||||
import uuid
|
||||
|
||||
from flask import url_for
|
||||
|
||||
|
||||
def get_url(endpoint_or_url, **kwargs):
|
||||
if endpoint_or_url == '':
|
||||
return
|
||||
if endpoint_or_url.startswith(('https://', 'http://', '/')):
|
||||
return endpoint_or_url
|
||||
else:
|
||||
return url_for(endpoint_or_url, **kwargs)
|
||||
|
||||
|
||||
#: generate a random filename, replacement for werkzeug.secure_filename
|
||||
def random_filename(old_filename):
|
||||
ext = os.path.splitext(old_filename)[1]
|
||||
new_filename = uuid.uuid4().hex + ext
|
||||
return new_filename
|
||||
Reference in New Issue
Block a user