678 lines
26 KiB
Python
678 lines
26 KiB
Python
# coding: utf-8
|
||
|
||
from filebrowser.actions import flip_horizontal, flip_vertical, rotate_90_clockwise, rotate_90_counterclockwise, rotate_180
|
||
import os
|
||
import re
|
||
import json
|
||
from time import gmtime, strftime, localtime, time
|
||
|
||
from django import forms
|
||
from django import VERSION as DJANGO_VERSION
|
||
from django.contrib import messages
|
||
from django.contrib.admin.sites import site as admin_site
|
||
from django.utils.module_loading import import_string
|
||
from django.contrib.admin.views.decorators import staff_member_required
|
||
from django.core.files.storage import DefaultStorage, default_storage, FileSystemStorage
|
||
from django.core.paginator import Paginator, InvalidPage, EmptyPage
|
||
try:
|
||
from django.urls import reverse, get_urlconf, get_resolver
|
||
except ImportError:
|
||
from django.core.urlresolvers import reverse, get_urlconf, get_resolver
|
||
from django.http import HttpResponseRedirect, HttpResponseBadRequest
|
||
from django.shortcuts import render, HttpResponse
|
||
from django.template import RequestContext as Context
|
||
from django.template.response import TemplateResponse
|
||
from django.utils.encoding import smart_str
|
||
from django.utils.translation import gettext as _
|
||
from django.views.decorators.cache import never_cache
|
||
from django.views.decorators.clickjacking import xframe_options_sameorigin
|
||
from django.views.decorators.csrf import csrf_exempt
|
||
|
||
from filebrowser import signals
|
||
from filebrowser.base import FileListing, FileObject
|
||
from filebrowser.decorators import path_exists, file_exists
|
||
from filebrowser.storage import FileSystemStorageMixin
|
||
from filebrowser.templatetags.fb_tags import query_helper
|
||
from filebrowser.utils import convert_filename
|
||
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, UPLOAD_TEMPDIR, ADMIN_CUSTOM
|
||
)
|
||
|
||
|
||
# This use admin_custom and not admin.sites.site of Django.
|
||
admin_site = import_string(ADMIN_CUSTOM) if ADMIN_CUSTOM else admin_site
|
||
|
||
|
||
# Add some required methods to FileSystemStorage
|
||
if FileSystemStorageMixin not in FileSystemStorage.__bases__:
|
||
FileSystemStorage.__bases__ += (FileSystemStorageMixin,)
|
||
|
||
|
||
# This cache contains all *instantiated* FileBrowser sites
|
||
_sites_cache = {}
|
||
|
||
|
||
def get_site_dict(app_name='filebrowser'):
|
||
"""
|
||
Return a dict with all *deployed* FileBrowser sites that have
|
||
a given app_name.
|
||
"""
|
||
if app_name not in _sites_cache:
|
||
return {}
|
||
# Get names of all deployed filebrowser sites with a give app_name
|
||
deployed = get_resolver(get_urlconf()).app_dict[app_name]
|
||
# Get the deployed subset from the cache
|
||
return dict((k, v) for k, v in _sites_cache[app_name].items() if k in deployed)
|
||
|
||
|
||
def register_site(app_name, site_name, site):
|
||
"""
|
||
Add a site into the site dict.
|
||
"""
|
||
if app_name not in _sites_cache:
|
||
_sites_cache[app_name] = {}
|
||
_sites_cache[app_name][site_name] = site
|
||
|
||
|
||
def get_default_site(app_name='filebrowser'):
|
||
"""
|
||
Returns the default site. This function uses Django's url resolution method to
|
||
obtain the name of the default site.
|
||
"""
|
||
# Get the name of the default site:
|
||
resolver = get_resolver(get_urlconf())
|
||
name = 'filebrowser'
|
||
|
||
# Django's default name resolution method (see django.core.urlresolvers.reverse())
|
||
app_list = resolver.app_dict[app_name]
|
||
if name not in app_list:
|
||
name = app_list[0]
|
||
|
||
return get_site_dict()[name]
|
||
|
||
|
||
def get_breadcrumbs(query, path):
|
||
"""
|
||
Get breadcrumbs.
|
||
"""
|
||
|
||
breadcrumbs = []
|
||
dir_query = ""
|
||
if path:
|
||
for item in path.split(os.sep):
|
||
dir_query = os.path.join(dir_query, item)
|
||
breadcrumbs.append([item, dir_query])
|
||
return breadcrumbs
|
||
|
||
|
||
def get_filterdate(filter_date, date_time):
|
||
"""
|
||
Get filterdate.
|
||
"""
|
||
|
||
returnvalue = ''
|
||
date_year = strftime("%Y", gmtime(date_time))
|
||
date_month = strftime("%m", gmtime(date_time))
|
||
date_day = strftime("%d", gmtime(date_time))
|
||
if filter_date == 'today' and int(date_year) == int(localtime()[0]) and int(date_month) == int(localtime()[1]) and int(date_day) == int(localtime()[2]):
|
||
returnvalue = 'true'
|
||
elif filter_date == 'thismonth' and date_time >= time() - 2592000:
|
||
returnvalue = 'true'
|
||
elif filter_date == 'thisyear' and int(date_year) == int(localtime()[0]):
|
||
returnvalue = 'true'
|
||
elif filter_date == 'past7days' and date_time >= time() - 604800:
|
||
returnvalue = 'true'
|
||
elif filter_date == '':
|
||
returnvalue = 'true'
|
||
return returnvalue
|
||
|
||
|
||
def get_settings_var(directory=DIRECTORY):
|
||
"""
|
||
Get settings variables used for FileBrowser listing.
|
||
"""
|
||
|
||
settings_var = {}
|
||
# Main
|
||
# Extensions/Formats (for FileBrowseField)
|
||
settings_var['EXTENSIONS'] = EXTENSIONS
|
||
settings_var['SELECT_FORMATS'] = SELECT_FORMATS
|
||
# Versions
|
||
settings_var['ADMIN_VERSIONS'] = ADMIN_VERSIONS
|
||
settings_var['ADMIN_THUMBNAIL'] = ADMIN_THUMBNAIL
|
||
# FileBrowser Options
|
||
settings_var['MAX_UPLOAD_SIZE'] = MAX_UPLOAD_SIZE
|
||
# Normalize Filenames
|
||
settings_var['NORMALIZE_FILENAME'] = NORMALIZE_FILENAME
|
||
# Convert Filenames
|
||
settings_var['CONVERT_FILENAME'] = CONVERT_FILENAME
|
||
# Traverse directories when searching
|
||
settings_var['SEARCH_TRAVERSE'] = SEARCH_TRAVERSE
|
||
return settings_var
|
||
|
||
|
||
def handle_file_upload(path, file, site):
|
||
"""
|
||
Handle File Upload.
|
||
"""
|
||
|
||
uploadedfile = None
|
||
try:
|
||
file_path = os.path.join(path, file.name)
|
||
uploadedfile = site.storage.save(file_path, file)
|
||
except Exception as inst:
|
||
raise inst
|
||
return uploadedfile
|
||
|
||
|
||
def filebrowser_view(view):
|
||
"Only let staff browse the files"
|
||
return staff_member_required(never_cache(xframe_options_sameorigin(view)))
|
||
|
||
|
||
class FileBrowserSite(object):
|
||
"""
|
||
A filebrowser.site defines admin views for browsing your servers media files.
|
||
"""
|
||
filelisting_class = FileListing
|
||
|
||
def __init__(self, name=None, app_name='filebrowser', storage=default_storage):
|
||
self.name = name
|
||
self.app_name = app_name
|
||
self.storage = storage
|
||
|
||
self._actions = {}
|
||
self._global_actions = self._actions.copy()
|
||
|
||
# Register this site in the global site cache
|
||
register_site(self.app_name, self.name, self)
|
||
|
||
# Per-site settings:
|
||
self.directory = DIRECTORY
|
||
|
||
def _directory_get(self):
|
||
"Set directory"
|
||
return self._directory
|
||
|
||
def _directory_set(self, val):
|
||
"Get directory"
|
||
self._directory = val
|
||
|
||
directory = property(_directory_get, _directory_set)
|
||
|
||
def get_urls(self):
|
||
"URLs for a filebrowser.site"
|
||
from django.urls import re_path
|
||
|
||
# filebrowser urls (views)
|
||
urlpatterns = [
|
||
re_path(r'^browse/$', path_exists(self,
|
||
filebrowser_view(self.browse)), name="fb_browse"),
|
||
re_path(r'^createdir/', path_exists(self,
|
||
filebrowser_view(self.createdir)), name="fb_createdir"),
|
||
re_path(r'^upload/', path_exists(self,
|
||
filebrowser_view(self.upload)), name="fb_upload"),
|
||
re_path(r'^delete_confirm/$', file_exists(self, path_exists(self,
|
||
filebrowser_view(self.delete_confirm))), name="fb_delete_confirm"),
|
||
re_path(r'^delete/$', file_exists(self, path_exists(self,
|
||
filebrowser_view(self.delete))), name="fb_delete"),
|
||
re_path(r'^detail/$', file_exists(self, path_exists(self,
|
||
filebrowser_view(self.detail))), name="fb_detail"),
|
||
re_path(r'^version/$', file_exists(self, path_exists(self,
|
||
filebrowser_view(self.version))), name="fb_version"),
|
||
re_path(r'^upload_file/$', staff_member_required(
|
||
csrf_exempt(self._upload_file)), name="fb_do_upload"),
|
||
]
|
||
return urlpatterns
|
||
|
||
def add_action(self, action, name=None):
|
||
"""
|
||
Register an action to be available globally.
|
||
"""
|
||
name = name or action.__name__
|
||
# Check/create short description
|
||
if not hasattr(action, 'short_description'):
|
||
action.short_description = action.__name__.replace(
|
||
"_", " ").capitalize()
|
||
# Check/create applies-to filter
|
||
if not hasattr(action, 'applies_to'):
|
||
action.applies_to = lambda x: True
|
||
self._actions[name] = action
|
||
self._global_actions[name] = action
|
||
|
||
def disable_action(self, name):
|
||
"""
|
||
Disable a globally-registered action. Raises KeyError for invalid names.
|
||
"""
|
||
del self._actions[name]
|
||
|
||
def get_action(self, name):
|
||
"""
|
||
Explicitally get a registered global action wheather it's enabled or
|
||
not. Raises KeyError for invalid names.
|
||
"""
|
||
return self._global_actions[name]
|
||
|
||
def applicable_actions(self, fileobject):
|
||
"""
|
||
Return a list of tuples (name, action) of actions applicable to a given fileobject.
|
||
"""
|
||
res = []
|
||
for name, action in self.actions:
|
||
if action.applies_to(fileobject):
|
||
res.append((name, action))
|
||
return res
|
||
|
||
@property
|
||
def actions(self):
|
||
"""
|
||
Get all the enabled actions as a list of (name, func). The list
|
||
is sorted alphabetically by actions names
|
||
"""
|
||
res = list(self._actions.items())
|
||
res.sort(key=lambda name_func: name_func[0])
|
||
return res
|
||
|
||
@property
|
||
def urls(self):
|
||
"filebrowser.site URLs"
|
||
return self.get_urls(), self.app_name, self.name
|
||
|
||
def browse(self, request):
|
||
"Browse Files/Directories."
|
||
filter_re = []
|
||
for exp in EXCLUDE:
|
||
filter_re.append(re.compile(exp))
|
||
|
||
# do not filter if VERSIONS_BASEDIR is being used
|
||
if not VERSIONS_BASEDIR:
|
||
for k, v in VERSIONS.items():
|
||
exp = (r'_%s(%s)$') % (k, '|'.join(EXTENSION_LIST))
|
||
filter_re.append(re.compile(exp, re.IGNORECASE))
|
||
|
||
def filter_browse(item):
|
||
"Defining a browse filter"
|
||
filtered = item.filename.startswith('.')
|
||
for re_prefix in filter_re:
|
||
if re_prefix.search(item.filename):
|
||
filtered = True
|
||
if filtered:
|
||
return False
|
||
return True
|
||
|
||
query = request.GET.copy()
|
||
path = u'%s' % os.path.join(self.directory, query.get('dir', ''))
|
||
|
||
filelisting = self.filelisting_class(
|
||
path,
|
||
filter_func=filter_browse,
|
||
sorting_by=query.get('o', DEFAULT_SORTING_BY),
|
||
sorting_order=query.get('ot', DEFAULT_SORTING_ORDER),
|
||
site=self)
|
||
|
||
files = []
|
||
if SEARCH_TRAVERSE and query.get("q"):
|
||
listing = filelisting.files_walk_filtered()
|
||
else:
|
||
listing = filelisting.files_listing_filtered()
|
||
|
||
# If we do a search, precompile the search pattern now
|
||
do_search = query.get("q")
|
||
if do_search:
|
||
re_q = re.compile(query.get("q").lower(), re.M)
|
||
|
||
filter_type = query.get('filter_type')
|
||
filter_date = query.get('filter_date')
|
||
|
||
for fileobject in listing:
|
||
# date/type filter
|
||
append = False
|
||
if (not filter_type or fileobject.filetype == filter_type) and (not filter_date or get_filterdate(filter_date, fileobject.date or 0)):
|
||
append = True
|
||
# search
|
||
if do_search and not re_q.search(fileobject.filename.lower()):
|
||
append = False
|
||
# append
|
||
if append:
|
||
files.append(fileobject)
|
||
|
||
filelisting.results_total = len(listing)
|
||
filelisting.results_current = len(files)
|
||
|
||
p = Paginator(files, LIST_PER_PAGE)
|
||
page_nr = request.GET.get('p', '1')
|
||
try:
|
||
page = p.page(page_nr)
|
||
except (EmptyPage, InvalidPage):
|
||
page = p.page(p.num_pages)
|
||
|
||
request.current_app = self.name
|
||
return TemplateResponse(request, 'filebrowser/index.html', dict(
|
||
admin_site.each_context(request),
|
||
**{
|
||
'p': p,
|
||
'page': page,
|
||
'filelisting': filelisting,
|
||
'query': query,
|
||
'title': _(u'FileBrowser'),
|
||
'is_popup': "pop" in request.GET, # ChangeList uses "pop"
|
||
'settings_var': get_settings_var(directory=self.directory),
|
||
'breadcrumbs': get_breadcrumbs(query, query.get('dir', '')),
|
||
'breadcrumbs_title': "",
|
||
'filebrowser_site': self,
|
||
}
|
||
))
|
||
|
||
def createdir(self, request):
|
||
"Create Directory"
|
||
from filebrowser.forms import CreateDirForm
|
||
query = request.GET
|
||
path = u'%s' % os.path.join(self.directory, query.get('dir', ''))
|
||
|
||
if request.method == 'POST':
|
||
form = CreateDirForm(path, request.POST, filebrowser_site=self)
|
||
if form.is_valid():
|
||
server_path = os.path.join(path, form.cleaned_data['name'])
|
||
try:
|
||
signals.filebrowser_pre_createdir.send(
|
||
sender=request, path=server_path, name=form.cleaned_data['name'], site=self)
|
||
self.storage.makedirs(server_path)
|
||
signals.filebrowser_post_createdir.send(
|
||
sender=request, path=server_path, name=form.cleaned_data['name'], site=self)
|
||
messages.add_message(request, messages.SUCCESS, _(
|
||
'The Folder %s was successfully created.') % form.cleaned_data['name'])
|
||
redirect_url = reverse("filebrowser:fb_browse", current_app=self.name) + query_helper(
|
||
query, "ot=desc,o=date", "ot,o,filter_type,filter_date,q,p")
|
||
return HttpResponseRedirect(redirect_url)
|
||
except OSError as e:
|
||
errno = e.args[0]
|
||
if errno == 13:
|
||
form.errors['name'] = forms.util.ErrorList(
|
||
[_('Permission denied.')])
|
||
else:
|
||
form.errors['name'] = forms.util.ErrorList(
|
||
[_('Error creating folder.')])
|
||
else:
|
||
form = CreateDirForm(path, filebrowser_site=self)
|
||
|
||
request.current_app = self.name
|
||
return TemplateResponse(request, 'filebrowser/createdir.html', dict(
|
||
admin_site.each_context(request),
|
||
**{
|
||
'form': form,
|
||
'query': query,
|
||
'title': _(u'New Folder'),
|
||
'is_popup': "pop" in request.GET,
|
||
'settings_var': get_settings_var(directory=self.directory),
|
||
'breadcrumbs': get_breadcrumbs(query, query.get('dir', '')),
|
||
'breadcrumbs_title': _(u'New Folder'),
|
||
'filebrowser_site': self
|
||
}
|
||
))
|
||
|
||
def upload(self, request):
|
||
"Multipe File Upload."
|
||
query = request.GET
|
||
|
||
request.current_app = self.name
|
||
return TemplateResponse(request, 'filebrowser/upload.html', dict(
|
||
admin_site.each_context(request),
|
||
**{
|
||
'query': query,
|
||
'title': _(u'Select files to upload'),
|
||
'is_popup': "pop" in request.GET,
|
||
'settings_var': get_settings_var(directory=self.directory),
|
||
'breadcrumbs': get_breadcrumbs(query, query.get('dir', '')),
|
||
'breadcrumbs_title': _(u'Upload'),
|
||
'filebrowser_site': self
|
||
}
|
||
))
|
||
|
||
def delete_confirm(self, request):
|
||
"Delete existing File/Directory."
|
||
query = request.GET
|
||
path = u'%s' % os.path.join(self.directory, query.get('dir', ''))
|
||
fileobject = FileObject(os.path.join(
|
||
path, query.get('filename', '')), site=self)
|
||
if fileobject.filetype == "Folder":
|
||
filelisting = self.filelisting_class(
|
||
os.path.join(path, fileobject.filename),
|
||
sorting_by=query.get('o', 'filename'),
|
||
sorting_order=query.get('ot', DEFAULT_SORTING_ORDER),
|
||
site=self)
|
||
filelisting = filelisting.files_walk_total()
|
||
if len(filelisting) > 100:
|
||
additional_files = len(filelisting) - 100
|
||
filelisting = filelisting[:100]
|
||
else:
|
||
additional_files = None
|
||
else:
|
||
filelisting = None
|
||
additional_files = None
|
||
|
||
request.current_app = self.name
|
||
return TemplateResponse(request, 'filebrowser/delete_confirm.html', dict(
|
||
admin_site.each_context(request),
|
||
**{
|
||
'fileobject': fileobject,
|
||
'filelisting': filelisting,
|
||
'additional_files': additional_files,
|
||
'query': query,
|
||
'title': _(u'Confirm delete'),
|
||
'is_popup': "pop" in request.GET,
|
||
'settings_var': get_settings_var(directory=self.directory),
|
||
'breadcrumbs': get_breadcrumbs(query, query.get('dir', '')),
|
||
'breadcrumbs_title': _(u'Confirm delete'),
|
||
'filebrowser_site': self
|
||
}
|
||
))
|
||
|
||
def delete(self, request):
|
||
"Delete existing File/Directory."
|
||
query = request.GET
|
||
path = u'%s' % os.path.join(self.directory, query.get('dir', ''))
|
||
fileobject = FileObject(os.path.join(
|
||
path, query.get('filename', '')), site=self)
|
||
|
||
if request.GET:
|
||
try:
|
||
signals.filebrowser_pre_delete.send(
|
||
sender=request, path=fileobject.path, name=fileobject.filename, site=self)
|
||
fileobject.delete_versions()
|
||
fileobject.delete()
|
||
signals.filebrowser_post_delete.send(
|
||
sender=request, path=fileobject.path, name=fileobject.filename, site=self)
|
||
messages.add_message(request, messages.SUCCESS, _(
|
||
'Successfully deleted %s') % fileobject.filename)
|
||
except OSError:
|
||
# TODO: define error-message
|
||
pass
|
||
redirect_url = reverse("filebrowser:fb_browse", current_app=self.name) + \
|
||
query_helper(query, "", "filename,filetype")
|
||
return HttpResponseRedirect(redirect_url)
|
||
|
||
def detail(self, request):
|
||
"""
|
||
Show detail page for a file.
|
||
Rename existing File/Directory (deletes existing Image Versions/Thumbnails).
|
||
"""
|
||
from filebrowser.forms import ChangeForm
|
||
query = request.GET
|
||
path = u'%s' % os.path.join(self.directory, query.get('dir', ''))
|
||
fileobject = FileObject(os.path.join(
|
||
path, query.get('filename', '')), site=self)
|
||
|
||
if request.method == 'POST':
|
||
form = ChangeForm(request.POST, path=path,
|
||
fileobject=fileobject, filebrowser_site=self)
|
||
if form.is_valid():
|
||
new_name = form.cleaned_data['name']
|
||
action_name = form.cleaned_data['custom_action']
|
||
try:
|
||
action_response = None
|
||
if action_name:
|
||
action = self.get_action(action_name)
|
||
# Pre-action signal
|
||
signals.filebrowser_actions_pre_apply.send(
|
||
sender=request, action_name=action_name, fileobject=[fileobject], site=self)
|
||
# Call the action to action
|
||
action_response = action(
|
||
request=request, fileobjects=[fileobject])
|
||
# Post-action signal
|
||
signals.filebrowser_actions_post_apply.send(sender=request, action_name=action_name, fileobject=[
|
||
fileobject], result=action_response, site=self)
|
||
if new_name != fileobject.filename:
|
||
signals.filebrowser_pre_rename.send(
|
||
sender=request, path=fileobject.path, name=fileobject.filename, new_name=new_name, site=self)
|
||
fileobject.delete_versions()
|
||
self.storage.move(fileobject.path, os.path.join(
|
||
fileobject.head, new_name))
|
||
signals.filebrowser_post_rename.send(
|
||
sender=request, path=fileobject.path, name=fileobject.filename, new_name=new_name, site=self)
|
||
messages.add_message(request, messages.SUCCESS, _(
|
||
'Renaming was successful.'))
|
||
if isinstance(action_response, HttpResponse):
|
||
return action_response
|
||
if "_continue" in request.POST:
|
||
redirect_url = reverse("filebrowser:fb_detail", current_app=self.name) + query_helper(
|
||
query, "filename=" + new_name, "filename")
|
||
else:
|
||
redirect_url = reverse(
|
||
"filebrowser:fb_browse", current_app=self.name) + query_helper(query, "", "filename")
|
||
return HttpResponseRedirect(redirect_url)
|
||
except OSError:
|
||
form.errors['name'] = forms.util.ErrorList([_('Error.')])
|
||
else:
|
||
form = ChangeForm(initial={"name": fileobject.filename},
|
||
path=path, fileobject=fileobject, filebrowser_site=self)
|
||
|
||
request.current_app = self.name
|
||
return TemplateResponse(request, 'filebrowser/detail.html', dict(
|
||
admin_site.each_context(request),
|
||
**{
|
||
'form': form,
|
||
'fileobject': fileobject,
|
||
'query': query,
|
||
'title': u'%s' % fileobject.filename,
|
||
'is_popup': "pop" in request.GET,
|
||
'settings_var': get_settings_var(directory=self.directory),
|
||
'breadcrumbs': get_breadcrumbs(query, query.get('dir', '')),
|
||
'breadcrumbs_title': u'%s' % fileobject.filename,
|
||
'filebrowser_site': self
|
||
}
|
||
))
|
||
|
||
def version(self, request):
|
||
"""
|
||
Version detail.
|
||
This just exists in order to select a version with a filebrowser–popup.
|
||
"""
|
||
query = request.GET
|
||
path = u'%s' % os.path.join(self.directory, query.get('dir', ''))
|
||
fileobject = FileObject(os.path.join(
|
||
path, query.get('filename', '')), site=self)
|
||
|
||
request.current_app = self.name
|
||
return TemplateResponse(request, 'filebrowser/version.html', dict(
|
||
admin_site.each_context(request),
|
||
**{
|
||
'fileobject': fileobject,
|
||
'query': query,
|
||
'settings_var': get_settings_var(directory=self.directory),
|
||
'filebrowser_site': self
|
||
}
|
||
))
|
||
|
||
def _upload_file(self, request):
|
||
"""
|
||
Upload file to the server.
|
||
|
||
If temporary is true, we upload to UPLOAD_TEMPDIR, 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.')
|
||
if len(request.FILES) > 1:
|
||
return HttpResponseBadRequest('Invalid request! Multiple files included.')
|
||
|
||
filedata = list(request.FILES.values())[0]
|
||
|
||
fb_uploadurl_re = re.compile(
|
||
r'^.*(%s)' % reverse("filebrowser:fb_upload", current_app=self.name))
|
||
folder = fb_uploadurl_re.sub('', 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}
|
||
return HttpResponse(json.dumps(ret_json))
|
||
|
||
signals.filebrowser_pre_upload.send(
|
||
sender=request, path=folder, file=filedata, site=self)
|
||
uploadedfile = handle_file_upload(path, filedata, site=self)
|
||
|
||
if file_already_exists and OVERWRITE_EXISTING:
|
||
old_file = smart_str(file_path)
|
||
new_file = smart_str(uploadedfile)
|
||
self.storage.move(new_file, old_file, allow_overwrite=True)
|
||
full_path = FileObject(
|
||
smart_str(old_file), site=self).path_full
|
||
else:
|
||
file_name = smart_str(uploadedfile)
|
||
filedata.name = os.path.relpath(file_name, path)
|
||
full_path = FileObject(
|
||
smart_str(file_name), site=self).path_full
|
||
|
||
# set permissions
|
||
if DEFAULT_PERMISSIONS is not None:
|
||
os.chmod(full_path, DEFAULT_PERMISSIONS)
|
||
|
||
f = FileObject(smart_str(file_name), site=self)
|
||
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,
|
||
'temp_filename': temp_filename,
|
||
'url': f.url,
|
||
}
|
||
return HttpResponse(json.dumps(ret_json), content_type="application/json")
|
||
|
||
|
||
storage = DefaultStorage()
|
||
# Default FileBrowser site
|
||
site = FileBrowserSite(name='filebrowser', storage=storage)
|
||
|
||
# Default actions
|
||
site.add_action(flip_horizontal)
|
||
site.add_action(flip_vertical)
|
||
site.add_action(rotate_90_clockwise)
|
||
site.add_action(rotate_90_counterclockwise)
|
||
site.add_action(rotate_180)
|