Skip to content

Commit

Permalink
filebrowseuploadfield (experimental), #236
Browse files Browse the repository at this point in the history
  • Loading branch information
sehmaschine committed Sep 9, 2015
1 parent 079cd4d commit b50670c
Show file tree
Hide file tree
Showing 11 changed files with 312 additions and 17 deletions.
2 changes: 1 addition & 1 deletion filebrowser/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
from django.utils.six import string_types

# FILEBROWSER IMPORTS
from filebrowser.settings import EXTENSIONS, VERSIONS, ADMIN_VERSIONS, VERSIONS_BASEDIR, VERSION_QUALITY, PLACEHOLDER, FORCE_PLACEHOLDER, SHOW_PLACEHOLDER, STRICT_PIL, IMAGE_MAXBLOCK, DEFAULT_PERMISSIONS
from filebrowser.settings import EXTENSIONS, VERSIONS, ADMIN_VERSIONS, VERSIONS_BASEDIR, VERSION_QUALITY, PLACEHOLDER, FORCE_PLACEHOLDER, SHOW_PLACEHOLDER, STRICT_PIL, IMAGE_MAXBLOCK, DEFAULT_PERMISSIONS, UPLOAD_TEMPDIR
from filebrowser.utils import path_strip, scale_and_crop
from django.utils.encoding import python_2_unicode_compatible, smart_str

Expand Down
131 changes: 131 additions & 0 deletions filebrowser/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,139 @@ def formfield(self, **kwargs):
return super(FileBrowseField, self).formfield(**defaults)


class FileBrowseUploadWidget(Input):
input_type = 'text'

class Media:
js = ('filebrowser/js/AddFileBrowser.js', 'filebrowser/js/fileuploader.js',)
css = {
'all': (os.path.join('/static/filebrowser/css/uploadfield.css'),)
}

def __init__(self, attrs=None):
super(FileBrowseUploadWidget, self).__init__(attrs)
self.site = attrs.get('site', '')
self.directory = attrs.get('directory', '')
self.extensions = attrs.get('extensions', '')
self.format = attrs.get('format', '')
self.upload_to = attrs.get('upload_to', '')
self.temp_upload_dir = attrs.get('temp_upload_dir', '')
if attrs is not None:
self.attrs = attrs.copy()
else:
self.attrs = {}
super(FileBrowseUploadWidget, self).__init__(attrs)

def render(self, name, value, attrs=None):
url = urlresolvers.reverse(self.site.name + ":fb_browse")
if value is None:
value = ""
if value != "" and not isinstance(value, FileObject):
value = FileObject(value, site=self.site)
final_attrs = self.build_attrs(attrs, type=self.input_type, name=name)
final_attrs['search_icon'] = '/static/filebrowser/img/filebrowser_icon_show.gif'
final_attrs['url'] = url
final_attrs['directory'] = self.directory
final_attrs['extensions'] = self.extensions
final_attrs['format'] = self.format
final_attrs['upload_to'] = self.upload_to
final_attrs['temp_upload_dir'] = UPLOAD_TEMPDIR
final_attrs['ADMIN_THUMBNAIL'] = ADMIN_THUMBNAIL
if value != "":
try:
final_attrs['directory'] = os.path.split(value.original.path_relative_directory)[0]
except:
pass
return render_to_string("filebrowser/custom_upload_field.html", locals())


class FileBrowseUploadFormField(forms.CharField):

default_error_messages = {
'extension': _(u'Extension %(ext)s is not allowed. Only %(allowed)s is allowed.'),
}

def __init__(self, max_length=None, min_length=None, site=None, directory=None, extensions=None, format=None, upload_to=None, temp_upload_dir=None, *args, **kwargs):
self.max_length, self.min_length = max_length, min_length
self.site = site
self.directory = directory
self.extensions = extensions
if format:
self.format = format or ''
self.extensions = extensions or EXTENSIONS.get(format)
self.upload_to = upload_to
self.temp_upload_dir = temp_upload_dir
super(FileBrowseUploadFormField, self).__init__(*args, **kwargs)

def clean(self, value):
value = super(FileBrowseUploadFormField, self).clean(value)
if value == '':
return value
file_extension = os.path.splitext(value)[1].lower()
if self.extensions and file_extension not in self.extensions:
raise forms.ValidationError(self.error_messages['extension'] % {'ext': file_extension, 'allowed': ", ".join(self.extensions)})
return value


class FileBrowseUploadField(CharField):
"""
Model field which renders with an option to browse site.directory as well
as upload a file to a temporary folder (you still need to somehow move that
temporary file to an actual location when the model is being saved).
"""

description = "FileBrowseUploadField"
__metaclass__ = models.SubfieldBase

def __init__(self, *args, **kwargs):
self.site = kwargs.pop('site', site)
self.directory = kwargs.pop('directory', '')
self.extensions = kwargs.pop('extensions', '')
self.format = kwargs.pop('format', '')
self.upload_to = kwargs.pop('upload_to', '')
self.temp_upload_dir = kwargs.pop('temp_upload_dir', '')
return super(FileBrowseUploadField, self).__init__(*args, **kwargs)

def to_python(self, value):
if not value or isinstance(value, FileObject):
return value
return FileObject(value, site=self.site)

def get_db_prep_value(self, value, connection, prepared=False):
if not value:
return value
return value.path

def value_to_string(self, obj):
value = self._get_val_from_obj(obj)
if not value:
return value
return value.path

def formfield(self, **kwargs):
attrs = {}
attrs["site"] = self.site
attrs["directory"] = self.directory
attrs["extensions"] = self.extensions
attrs["format"] = self.format
attrs["upload_to"] = self.upload_to
attrs["temp_upload_dir"] = self.temp_upload_dir
defaults = {
'form_class': FileBrowseUploadFormField,
'widget': FileBrowseUploadWidget(attrs=attrs),
'site': self.site,
'directory': self.directory,
'extensions': self.extensions,
'format': self.format,
'upload_to': self.upload_to,
'temp_upload_dir': self.temp_upload_dir
}
return super(FileBrowseUploadField, self).formfield(**defaults)


try:
from south.modelsinspector import add_introspection_rules
add_introspection_rules([], ["^filebrowser\.fields\.FileBrowseField"])
add_introspection_rules([], ["^filebrowser\.fields\.FileBrowseUploadField"])
except:
pass
9 changes: 7 additions & 2 deletions filebrowser/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@
from django.conf import settings
from django.utils.translation import ugettext_lazy as _

# Main FileBrowser Directory. This has to be a directory within MEDIA_ROOT.
# Leave empty in order to browse all files under MEDIA_ROOT.
# Main FileBrowser Directory. Relative to site.storage.location.
# DO NOT USE A SLASH AT THE BEGINNING, DO NOT FORGET THE TRAILING SLASH AT THE END.
DIRECTORY = getattr(settings, "FILEBROWSER_DIRECTORY", 'uploads/')

Expand Down Expand Up @@ -96,6 +95,12 @@
# Overwrite existing files on upload
OVERWRITE_EXISTING = getattr(settings, "FILEBROWSER_OVERWRITE_EXISTING", True)

# UPLOAD

# Directory to Save temporary uploaded files (FileBrowseUploadField)
# Relative to site.storage.location.
UPLOAD_TEMPDIR = getattr(settings, 'FILEBROWSER_UPLOAD_TEMPDIR', '_temp')

# EXTRA TRANSLATION STRINGS

# The following strings are not available within views or templates
Expand Down
34 changes: 20 additions & 14 deletions filebrowser/sites.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,29 +27,20 @@
from django.utils.encoding import smart_unicode as smart_text

# FILEBROWSER IMPORTS
from filebrowser.settings import STRICT_PIL, DIRECTORY, EXTENSIONS, SELECT_FORMATS, ADMIN_VERSIONS, ADMIN_THUMBNAIL, MAX_UPLOAD_SIZE,\
from filebrowser.settings import DIRECTORY, EXTENSIONS, SELECT_FORMATS, ADMIN_VERSIONS, ADMIN_THUMBNAIL, MAX_UPLOAD_SIZE,\
NORMALIZE_FILENAME, CONVERT_FILENAME, SEARCH_TRAVERSE, EXCLUDE, VERSIONS, VERSIONS_BASEDIR, EXTENSION_LIST, DEFAULT_SORTING_BY, DEFAULT_SORTING_ORDER,\
LIST_PER_PAGE, OVERWRITE_EXISTING, DEFAULT_PERMISSIONS
LIST_PER_PAGE, OVERWRITE_EXISTING, DEFAULT_PERMISSIONS, UPLOAD_TEMPDIR
from filebrowser.templatetags.fb_tags import query_helper
from filebrowser.base import FileListing, FileObject
from filebrowser.decorators import path_exists, file_exists
from filebrowser.storage import FileSystemStorageMixin, StorageMixin
from filebrowser.storage import FileSystemStorageMixin
from filebrowser.utils import convert_filename
from filebrowser import signals

# Add some required methods to FileSystemStorage
if FileSystemStorageMixin not in FileSystemStorage.__bases__:
FileSystemStorage.__bases__ += (FileSystemStorageMixin,)

# PIL import
if STRICT_PIL:
from PIL import Image
else:
try:
from PIL import Image
except ImportError:
import Image

# JSON import
try:
import json
Expand Down Expand Up @@ -531,9 +522,14 @@ def version(self, request):
def _upload_file(self, request):
"""
Upload file to the server.
If temporary is true, we upload to UPLOAD_TEMP_DIR, otherwise
we upload to site.directory
"""
if request.method == "POST":
folder = request.GET.get('folder', '')
temporary = request.GET.get('temporary', '')
temp_filename = None

if len(request.FILES) == 0:
return HttpResponseBadRequest('Invalid request! No files included.')
Expand All @@ -545,14 +541,24 @@ def _upload_file(self, request):
fb_uploadurl_re = re.compile(r'^.*(%s)' % reverse("filebrowser:fb_upload", current_app=self.name))
folder = fb_uploadurl_re.sub('', folder)

path = os.path.join(self.directory, folder)
# temporary upload folder should be outside self.directory
if folder == UPLOAD_TEMPDIR and temporary == "true":
path = folder
else:
path = os.path.join(self.directory, folder)
# we convert the filename before uploading in order
# to check for existing files/folders
file_name = convert_filename(filedata.name)
filedata.name = file_name
file_path = os.path.join(path, file_name)
file_already_exists = self.storage.exists(file_path)

# construct temporary filename by adding the upload folder, because
# otherwise we don't have any clue if the file has temporary been
# uploaded or not
if folder == UPLOAD_TEMPDIR and temporary == "true":
temp_filename = os.path.join(folder, file_name)

# Check for name collision with a directory
if file_already_exists and self.storage.isdir(file_path):
ret_json = {'success': False, 'filename': file_name}
Expand All @@ -579,7 +585,7 @@ def _upload_file(self, request):
signals.filebrowser_post_upload.send(sender=request, path=folder, file=f, site=self)

# let Ajax Upload know whether we saved it or not
ret_json = {'success': True, 'filename': f.filename}
ret_json = {'success': True, 'filename': f.filename, 'temp_filename': temp_filename}
return HttpResponse(json.dumps(ret_json), content_type="application/json")

storage = DefaultStorage()
Expand Down
1 change: 1 addition & 0 deletions filebrowser/static/filebrowser/css/uploadfield.css

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added filebrowser/static/filebrowser/img/fb-upload.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit b50670c

Please sign in to comment.