Commit 18267649 authored by Sergey Markelov's avatar Sergey Markelov

Merge remote-tracking branch 'remotes/upstream/master'

parents 26742fb6 cfeaa030
......@@ -292,8 +292,8 @@ class BaseView(with_metaclass(AdminViewMeta, BaseViewClass)):
"""
This method will be executed before calling any view method.
By default, it will check if the admin class is accessible and if it is not it will
throw HTTP 404 error.
It will execute the ``inaccessible_callback`` if the view is not
accessible.
:param name:
View function name
......@@ -301,7 +301,17 @@ class BaseView(with_metaclass(AdminViewMeta, BaseViewClass)):
View function arguments
"""
if not self.is_accessible():
return abort(403)
return self.inaccessible_callback(name, **kwargs)
def inaccessible_callback(self, name, **kwargs):
"""
Handle the response to inaccessible views.
By default, it throw HTTP 403 error. Override this method to
customize the behaviour.
"""
return abort(403)
@property
def _debug(self):
......
......@@ -334,8 +334,8 @@ class ModelView(BaseModelView):
# TODO: Optimize me
for pk in ids:
self.coll.remove({'_id': self._get_valid_id(pk)})
count += 1
if self.delete_model(self.get_one(pk)):
count += 1
flash(ngettext('Model was successfully deleted.',
'%(count)s models were successfully deleted.',
......
......@@ -333,6 +333,9 @@ class ModelView(BaseModelView):
else:
column = p.columns[0]
if column.foreign_keys:
continue
if not self.column_display_pk and column.primary_key:
continue
......@@ -420,12 +423,12 @@ class ModelView(BaseModelView):
Verify if the provided column type is text-based.
:returns:
``True`` for ``String``, ``Unicode``, ``Text``, ``UnicodeText``
``True`` for ``String``, ``Unicode``, ``Text``, ``UnicodeText``, ``varchar``
"""
if name:
name = name.lower()
return name in ('string', 'unicode', 'text', 'unicodetext')
return name in ('string', 'unicode', 'text', 'unicodetext', 'varchar')
def scaffold_filters(self, name):
"""
......@@ -605,6 +608,11 @@ class ModelView(BaseModelView):
def get_count_query(self):
"""
Return a the count query for the model type
A query(self.model).count() approach produces an excessive
subquery, so query(func.count('*')) should be used instead.
See #45a2723 commit message for details.
"""
return self.session.query(func.count('*')).select_from(self.model)
......@@ -783,7 +791,7 @@ class ModelView(BaseModelView):
flash(gettext('Integrity error. %(message)s', message=exc.message), 'error')
return True
return super(BaseModelView, self).handle_view_exception(exc)
return super(ModelView, self).handle_view_exception(exc)
# Model handlers
def create_model(self, form):
......@@ -882,8 +890,8 @@ class ModelView(BaseModelView):
count = 0
for m in query.all():
self.session.delete(m)
count += 1
if self.delete_model(m):
count += 1
self.session.commit()
......
......@@ -181,9 +181,10 @@ class FileUploadField(fields.StringField):
map(lambda x: x.lower(), self.allowed_extensions))
def pre_validate(self, form):
if (self.data and
isinstance(self.data, FileStorage) and
not self.is_file_allowed(self.data.filename)):
if (self.data
and self.data.filename
and isinstance(self.data, FileStorage)
and not self.is_file_allowed(self.data.filename)):
raise ValidationError(gettext('Invalid file extension'))
def process(self, formdata, data=unset_value):
......@@ -237,7 +238,7 @@ class FileUploadField(fields.StringField):
def _save_file(self, data, filename):
path = self._get_path(filename)
if not op.exists(op.dirname(path)):
os.makedirs(os.path.dirname(path), self.permission)
os.makedirs(os.path.dirname(path), self.permission | 0o111)
data.save(path)
......@@ -355,7 +356,9 @@ class ImageUploadField(FileUploadField):
def pre_validate(self, form):
super(ImageUploadField, self).pre_validate(form)
if self.data and isinstance(self.data, FileStorage):
if (self.data and
isinstance(self.data, FileStorage) and
self.data.filename):
try:
self.image = Image.open(self.data)
except Exception as e:
......
......@@ -366,13 +366,13 @@ class BaseModelView(BaseView, ActionsMixin):
}
}
Note, changing the format of a DateTimeField will require changes to both form_widget_args and form_args:
Note, changing the format of a DateTimeField will require changes to both form_widget_args and form_args::
form_args = dict(
start=dict(format='%Y-%m-%d %H:%M') # changes how the input is parsed by strptime
start=dict(format='%Y-%m-%d %I:%M %p') # changes how the input is parsed by strptime (12 hour time)
)
form_widget_args = dict(
start={'data-date-format': u'yyyy-mm-dd hh:ii'} # changes how the DateTimeField displays the time
start={'data-date-format': u'yyyy-mm-dd HH:ii P', 'data-show-meridian': 'True'} # changes how the DateTimeField displays the time
)
"""
......
......@@ -140,7 +140,7 @@
var $parentForm = $el.parent().closest('.inline-field');
if ($parentForm.length > 0) {
if ($parentForm.length > 0 && elID.indexOf($parentForm.attr('id')) !== 0) {
id = $parentForm.attr('id') + '-' + elID;
}
......
from nose.tools import ok_, eq_, raises
from flask import Flask, request
from flask import Flask, request, abort
from flask.views import MethodView
from flask.ext.admin import base
......@@ -232,6 +232,20 @@ def test_permissions():
eq_(rv.status_code, 403)
def test_inaccessible_callback():
app = Flask(__name__)
admin = base.Admin(app)
view = MockView()
admin.add_view(view)
client = app.test_client()
view.allow_access = False
view.inaccessible_callback = lambda *args, **kwargs: abort(418)
rv = client.get('/admin/mockview/')
eq_(rv.status_code, 418)
def get_visibility():
app = Flask(__name__)
admin = base.Admin(app)
......
This diff is collapsed.
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