Commit 4cc09efa authored by mrjoes's avatar mrjoes

File admin mass-actions

parent 373448cb
......@@ -43,7 +43,7 @@ class ActionsMixin(object):
self._actions_data[name] = (attr, text, desc)
def is_action_allowed(self, name):
return True
return name not in self.disallowed_actions
def get_actions_list(self):
actions = []
......
......@@ -12,6 +12,7 @@ from werkzeug import secure_filename
from flask import flash, url_for, redirect, abort, request
from flask.ext.admin.base import BaseView, expose
from flask.ext.admin.actions import action, ActionsMixin
from flask.ext.admin.babel import gettext, lazy_gettext
from flask.ext.admin import form
from flask.ext import wtf
......@@ -54,7 +55,7 @@ class UploadForm(form.BaseForm):
raise wtf.ValidationError(gettext('Invalid file type.'))
class FileAdmin(BaseView):
class FileAdmin(BaseView, ActionsMixin):
"""
Simple file-management interface.
......@@ -151,6 +152,8 @@ class FileAdmin(BaseView):
self.base_path = base_path
self.base_url = base_url
self.init_actions()
self._on_windows = platform.system() == 'Windows'
# Convert allowed_extensions to set for quick validation
......@@ -277,6 +280,12 @@ class FileAdmin(BaseView):
return base_path, directory, path
def is_action_allowed(self, name):
if name == 'delete' and not self.can_delete:
return False
return True
@expose('/')
@expose('/b/<path:path>')
def index(self, path=None):
......@@ -315,12 +324,17 @@ class FileAdmin(BaseView):
accumulator.append(n)
breadcrumbs.append((n, op.join(*accumulator)))
# Actions
actions, actions_confirmation = self.get_actions_list()
return self.render(self.list_template,
dir_path=path,
breadcrumbs=breadcrumbs,
get_dir_url=self._get_dir_url,
get_file_url=self._get_file_url,
items=items)
items=items,
actions=actions,
actions_confirmation=actions_confirmation)
@expose('/upload/', methods=('GET', 'POST'))
@expose('/upload/<path:path>', methods=('GET', 'POST'))
......@@ -466,3 +480,21 @@ class FileAdmin(BaseView):
path=op.dirname(path),
name=op.basename(path),
dir_url=return_url)
@expose('/action/', methods=('POST',))
def action_view(self):
return self.handle_action()
# Actions
@action('delete',
lazy_gettext('Delete'),
lazy_gettext('Are you sure you want to delete these files?'))
def action_delete(self, items):
for path in items:
base_path, full_path, path = self._normalize_path(path)
try:
os.remove(full_path)
flash(gettext('File "%(name)s" was successfully deleted.', name=path))
except Exception, ex:
flash(gettext('Failed to delete file: %(name)s', name=ex), 'error')
{% macro dropdown(actions) -%}
{% if actions %}
<li class="dropdown">
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
{{ _gettext('With selected')}}<b class="caret"></b>
</a>
<ul id="action_list" class="dropdown-menu">
{% for p in actions %}
<li>
<a href="#" onclick="return modelActions.execute('{{ p[0] }}');">{{ _gettext(p[1]) }}</a>
</li>
{% endfor %}
</ul>
</li>
{% endif %}
{% macro dropdown(btn_class='dropdown-toggle') -%}
<a class="{{ btn_class }}" data-toggle="dropdown" href="#">
{{ _gettext('With selected')}}<b class="caret"></b>
</a>
<ul class="dropdown-menu">
{% for p in actions %}
<li>
<a href="#" onclick="return modelActions.execute('{{ p[0] }}');">{{ _gettext(p[1]) }}</a>
</li>
{% endfor %}
</ul>
{% endmacro %}
{% macro form(actions, view) %}
{% macro form(actions, url) %}
{% if actions %}
<form id="action_form" action="{{ url_for(view) }}" method="POST" style="display: none">
<form id="action_form" action="{{ url }}" method="POST" style="display: none">
<input type="hidden" id="action" name="action" />
</form>
{% endif %}
......
{% extends 'admin/master.html' %}
{% import 'admin/lib.html' as lib with context %}
{% import 'admin/actions.html' as actionslib with context %}
{% block body %}
<ul class="breadcrumb">
......@@ -21,6 +22,11 @@
<table class="table table-striped table-bordered model-list">
<thead>
<tr>
{% if actions %}
<th class="span1">
<input type="checkbox" name="rowtoggle" class="action-rowtoggle" />
</th>
{% endif %}
<th class="span1">&nbsp;</th>
<th>Name</th>
<th>Size</th>
......@@ -28,6 +34,13 @@
</thead>
{% for name, path, is_dir, size in items %}
<tr>
{% if actions %}
<td>
{% if not is_dir %}
<input type="checkbox" name="rowid" class="action-checkbox" value="{{ path }}" />
{% endif %}
</td>
{% endif %}
<td>
{% if admin_view.can_rename and path and name != '..' %}
<a class="icon" href="{{ url_for('.rename', path=path) }}">
......@@ -71,10 +84,29 @@
</tr>
{% endfor %}
</table>
{% if admin_view.can_upload %}
<a class="btn btn-primary btn-large" href="{{ get_dir_url('.upload', path=dir_path) }}">{{ _gettext('Upload File') }}</a>
{% endif %}
{% if admin_view.can_mkdir %}
<a class="btn btn-primary btn-large" href="{{ get_dir_url('.mkdir', path=dir_path) }}">{{ _gettext('Create Directory') }}</a>
{% endif %}
<div class="btn-toolbar">
{% if admin_view.can_upload %}
<div class="btn-group">
<a class="btn btn-primary btn-large" href="{{ get_dir_url('.upload', path=dir_path) }}">{{ _gettext('Upload File') }}</a>
</div>
{% endif %}
{% if admin_view.can_mkdir %}
<div class="btn-group">
<a class="btn btn-primary btn-large" href="{{ get_dir_url('.mkdir', path=dir_path) }}">{{ _gettext('Create Directory') }}</a>
</div>
{% endif %}
{% if actions %}
<div class="btn-group">
{{ actionslib.dropdown('dropdown-toggle btn btn-primary btn-large') }}
</div>
{% endif %}
</div>
{{ actionslib.form(actions, url_for('.action_view')) }}
{% endblock %}
{% block tail %}
{{ actionslib.script(_gettext('Please select at least one file.'),
actions,
actions_confirmation) }}
{% endblock %}
......@@ -33,7 +33,11 @@
</li>
{% endif %}
{{ actionlib.dropdown(actions) }}
{% if actions %}
<li class="dropdown">
{{ actionlib.dropdown() }}
</li>
{% endif %}
{% if search_supported %}
<li>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment