Skip to content

Instantly share code, notes, and snippets.

@alanhamlett
Created November 30, 2018 00:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save alanhamlett/2942ff58b0263e11dcb8d376b149de43 to your computer and use it in GitHub Desktop.
Save alanhamlett/2942ff58b0263e11dcb8d376b149de43 to your computer and use it in GitHub Desktop.
Flask-Admin Example (replace dash with forward slash in file names)
# -*- coding: utf-8 -*-
"""
wakatime.admin
~~~~~~~~~~~~~~
Flask-Admin.
"""
from .views import admin
# -*- coding: utf-8 -*-
"""
wakatime.admin.utils
~~~~~~~~~~~~~~~~~~~~
Flask-Admin utilities.
"""
from flask import abort, redirect, request, url_for
from flask_admin import AdminIndexView, expose
from flask_admin.babel import lazy_gettext
from flask_admin.base import MenuLink
from flask_admin.contrib import sqla
from functools import wraps
from wakatime import app, utils
class FilterUUIDEqual(sqla.filters.BaseSQLAFilter):
def apply(self, query, value, *args):
if not utils.is_uuid4(value):
return query
return query.filter(self.column == value)
def operation(self):
return lazy_gettext('equals')
def admin_required(f):
@wraps(f)
def decorated(*args, **kwargs):
if not app.current_user.is_authenticated:
return redirect(url_for('views.login', next=request.url))
if not app.current_user.is_admin:
app.logger.debug('Not an admin')
abort(404)
return f(*args, **kwargs)
return decorated
def permission_required(permissions):
if not isinstance(permissions, (list, set, tuple)):
permissions = [permissions]
permissions = [x.upper() for x in permissions]
def decorator(method):
@wraps(method)
def f(*args, **kwargs):
if not app.current_user.is_authenticated:
return redirect(url_for('views.login', next=request.url))
users_permissions = app.current_user.permissions
if 'ALL' not in users_permissions:
for permission in permissions:
if permission not in users_permissions:
app.logger.debug('Missing permission: {0}'.format(permission))
abort(404)
return method(*args, **kwargs)
return f
return decorator
class AuthenticatedMenuLink(MenuLink):
def is_accessible(self):
return app.current_user.is_authenticated
class CustomAdminIndexView(AdminIndexView):
@expose('/')
@permission_required('admin')
def index(self):
if not app.current_user.is_authenticated:
return redirect(url_for('views.login', next=request.url))
return super(CustomAdminIndexView, self).index()
@expose('/login/')
def login_view(self):
return redirect(url_for('views.login', next=request.url))
@expose('/logout/')
def logout_view(self):
return redirect('/logout')
class CustomModelView(sqla.ModelView):
edit_template = 'admin/model/edit.html'
create_template = 'admin/model/create.html'
list_template = 'admin/model/custom_list.html'
page_size = 50
_include = None
class_attributes = [
'page_size',
'can_create',
'can_edit',
'can_delete',
'column_searchable_list',
'column_filters',
'column_exclude_list',
'column_default_sort',
]
def __init__(self, *args, **kwargs):
if 'exclude' in kwargs:
self.form_excluded_columns = kwargs['exclude']
del kwargs['exclude']
if 'include' in kwargs:
self._include = kwargs['include']
del kwargs['include']
for item in self.class_attributes:
if item in kwargs:
setattr(self, item, kwargs[item])
del kwargs[item]
super(CustomModelView, self).__init__(*args, **kwargs)
def get_list_columns(self):
if self._include:
return self.get_column_names(
only_columns=self.scaffold_list_columns() + self._include,
excluded_columns=self.column_exclude_list,
)
return super(CustomModelView, self).get_list_columns()
def is_accessible(self):
return app.current_user.is_authenticated and app.current_user.is_admin
def inaccessible_callback(self, name, **kwargs):
return abort(404)
# -*- coding: utf-8 -*-
"""
wakatime.admin.views
~~~~~~~~~~~~~~~~~~~~
Flask-Admin views.
"""
from flask_admin import Admin, BaseView, expose
from wakatime import app
from wakatime.admin.utils import (AuthenticatedMenuLink, CustomAdminIndexView,
CustomModelView, FilterUUIDEqual,
admin_required)
from wakatime.models import db, User
admin = Admin(app, index_view=CustomAdminIndexView(), template_mode='bootstrap3', base_template='admin/custom_base.html')
admin.add_link(AuthenticatedMenuLink(name='Logout', endpoint='admin.logout_view'))
class UsersView(BaseView):
@expose('/')
@admin_required
def index(self):
return self.render('admin/index.html')
admin.add_view(UsersView(name='Search', endpoint='users', category='Users'))
admin.add_view(CustomModelView(User, db.session, category='Users',
can_create=False, can_delete=False,
column_default_sort=('created_at', True),
exclude=['password', 'auth_clients', 'leaderboards', 'created_at', 'modified_at'],
column_exclude_list=['api_key', 'password', 'session_id', 'modified_at'],
column_filters=['email', 'username', FilterUUIDEqual(User.id, 'user_id')],
column_searchable_list=['email', 'username', 'timezone'],
))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment