Commits

Anonymous committed 9a6c60e

extended API with a public downloads URL function and template filter and a kwargs which allows for marking uploads as private (prepare_upload(private=True)), so e.g. an Amazon S3 backend could mark permissions accordingly. by default uploads are now public if it's supported by the backend. also, replaced the redirect backend with a public_url backend that directs downloads to a public download URL and added a backend that directs downloads to file.url (should only be used if file.url actually points to a publicly accessible download location)

Comments (0)

Files changed (7)

filetransfers/api.py

 from django.utils.importlib import import_module
 import mimetypes
 
-UPLOAD_BACKEND = getattr(settings, 'FILETRANSFERS_UPLOAD_BACKEND',
-                         'filetransfers.backends.default.prepare_upload')
-DOWNLOAD_BACKEND = getattr(settings, 'FILETRANSFERS_DOWNLOAD_BACKEND',
-                           'filetransfers.backends.default.serve_file')
+UPLOAD_BACKEND = getattr(settings,
+    'FILETRANSFERS_UPLOAD_BACKEND',
+    'filetransfers.backends.default.prepare_upload')
+DOWNLOAD_BACKEND = getattr(settings,
+    'FILETRANSFERS_DOWNLOAD_BACKEND',
+    'filetransfers.backends.default.serve_file')
+PUBLIC_DOWNLOAD_URL_BACKEND = getattr(settings,
+    'FILETRANSFERS_PUBLIC_DOWNLOAD_URL_BACKEND',
+    'filetransfers.backends.default.public_download_url')
 
 _backends_cache = {}
 
 # Public API
-def prepare_upload(request, url, backend=None):
-    # TODO: Support specifying maxmium file upload size and other constraints?
-    # Probably can't be done for all backends, so maybe the developer should
-    # always check these constraints after the upload?
+def prepare_upload(request, url, private=False, backend=None):
     handler = _load_backend(backend, UPLOAD_BACKEND)
-    result = handler(request, url)
+    result = handler(request, url, private=private)
     if isinstance(result, (tuple, list)):
         return result
     return result, {}
         content_type = mimetypes.guess_type(filename)[0]
     return handler(request, file, save_as=save_as, content_type=content_type)
 
+def public_download_url(file, backend=None):
+    handler = _load_backend(backend, PUBLIC_DOWNLOAD_URL_BACKEND)
+    return handler(file)
+
 # Internal utilities
 def _load_backend(backend, default_backend):
     if backend is None:

filetransfers/backends/default.py

 from django.http import HttpResponse
 from django.utils.encoding import smart_str
 
-def prepare_upload(request, url):
+def prepare_upload(request, url, **kwargs):
     """Directly uploads to the given URL"""
     return url
 
-def serve_file(request, file, save_as, content_type):
+def serve_file(request, file, save_as, content_type, **kwargs):
     """
     Serves the file in chunks for efficiency reasons, but the transfer still
     goes through Django itself, so it's much worse than using the web server,
         response['Content-Length'] = file.size
     return response
 
+def public_download_url(file, **kwargs):
+    """No public download URL"""
+    return None
+
 class ChunkedFile(object):
     def __init__(self, file):
         self.file = file

filetransfers/backends/public_url.py

+from django.conf import settings
+
+def public_download_url(file, **kwargs):
+    """
+    Directs downloads to a handler at settings.PUBLIC_DOWNLOADS_URL_BASE
+    """
+    return settings.PUBLIC_DOWNLOADS_URL_BASE + file.name

filetransfers/backends/redirect.py

-from django.conf import settings
-from django.http import HttpResponseRedirect
-from django.utils.encoding import smart_str
-
-def serve_file(request, file, save_as, content_type):
-    """
-    Redirects downloads to a handler at settings.FILETRANSFERS_BASE_REDIRECT_URL
-    """
-    return HttpResponseRedirect(smart_str(
-        settings.FILETRANSFERS_BASE_REDIRECT_URL + file.name))

filetransfers/backends/url.py

 from django.http import HttpResponseRedirect
 from django.utils.encoding import smart_str
 
-def serve_file(request, file, save_as, content_type):
+def serve_file(request, file, save_as, content_type, **kwargs):
     """Serves files by redirecting to file.url (e.g., useful for Amazon S3)"""
     return HttpResponseRedirect(smart_str(file.url))
+
+def public_download_url(file, **kwargs):
+    """Directs downloads to file.url (useful for normal file system storage)"""
+    return file.url

filetransfers/backends/xsendfile.py

 from django.http import HttpResponse
 from django.utils.encoding import smart_str
 
-def serve_file(request, file, save_as, content_type):
+def serve_file(request, file, save_as, content_type, **kwargs):
     """Lets the web server serve the file using the X-Sendfile extension"""
     response = HttpResponse(content_type=content_type)
     response['X-Sendfile'] = file.path

filetransfers/templatetags/filetransfers.py

 from django.template import Library
 from django.utils.safestring import mark_safe
 
+from ..api import public_download_url
+
 register = Library()
 
 _hidden_data_field = '<input type="hidden" name="%s" value="%s" />'
     if inputs:
         return mark_safe('<div style="display:none">%s</div>' % inputs)
     return ''
+
+register.filter(public_download_url)
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.