def __init__(self, app, url_prefix="/admin", title="flask-dashed", main_dashboard=None, endpoint='admin'): if not main_dashboard: from .dashboard import DefaultDashboard main_dashboard = DefaultDashboard self.blueprint = Blueprint(endpoint, __name__, static_folder='static', template_folder='templates') self.app = app self.url_prefix = url_prefix self.endpoint = endpoint self.title = title self.secure_functions = OrderedMultiDict() # Checks security for current path self.blueprint.before_request( lambda: self.check_path_security(request.path)) self.app.register_blueprint(self.blueprint, url_prefix=url_prefix) self.root_nodes = [] self._add_node(main_dashboard, '/', 'main-dashboard', 'dashboard') # Registers recursive_getattr filter self.app.jinja_env.filters['recursive_getattr'] = recursive_getattr
def __init__(self, app, url_prefix='/dashboard', title='dashboard', endpoint='dash'): self.app = app self.blueprint = Blueprint(endpoint, __name__, static_folder='static', template_folder='templates',) self.url_prefix = url_prefix self.title = title self._register_model = OrderedMultiDict() self._panels = OrderedMultiDict()
def test_ordered_multidict_encoding(): """"Make sure URLs are properly encoded from OrderedMultiDicts""" d = OrderedMultiDict() d.add('foo', 1) d.add('foo', 2) d.add('foo', 3) d.add('bar', 0) d.add('foo', 4) assert url_encode(d) == 'foo=1&foo=2&foo=3&bar=0&foo=4'
def __new__(cls, *args, **kwargs): if not cls.model: raise Exception('ModelAdminModule must provide `model` attribute') if not cls.list_fields: cls.list_fields = OrderedMultiDict() for column in cls.model.__table__._columns: cls.list_fields[column.name] = { 'label': column.name, 'column': getattr(cls.model, column.name) } if not cls.form_class: cls.form_class = model_form(cls.model, cls.db_session) return super(ModelAdminModule, cls).__new__(cls, *args, **kwargs)
class UserModule(ModelAdminModule): model = User db_session = db_session profile_alias = aliased(Profile) list_fields = OrderedMultiDict(( ('id', { 'label': 'id', 'column': User.id }), ('username', { 'label': 'username', 'column': User.username }), ('profile.name', { 'label': 'name', 'column': profile_alias.name }), ('profile.location', { 'label': 'location', 'column': profile_alias.location }), )) list_title = 'user list' searchable_fields = ['username', 'profile.name', 'profile.location'] order_by = ('id', 'desc') list_query_factory = model.query\ .outerjoin(profile_alias, 'profile')\ .options(contains_eager('profile', alias=profile_alias))\ form_class = UserForm def create_object(self): user = self.model() user.profile = Profile() return user
def __init__(self, app, url_prefix="/admin", title="flask-dashed", main_dashboard=None, endpoint="admin"): if not main_dashboard: from dashboard import DefaultDashboard main_dashboard = DefaultDashboard self.blueprint = Blueprint(endpoint, __name__, static_folder="static", template_folder="templates") self.app = app self.url_prefix = url_prefix self.endpoint = endpoint self.title = title self.secure_functions = OrderedMultiDict() # Checks security for current path self.blueprint.before_request(lambda: self.check_path_security(request.path)) self.app.register_blueprint(self.blueprint, url_prefix=url_prefix) self.root_nodes = [] self._add_node(main_dashboard, "/", "main-dashboard", "dashboard") # Registers recursive_getattr filter self.app.jinja_env.filters["recursive_getattr"] = recursive_getattr
class BookModule(ModelAdminModule): """Sample module with explicit eager loaded query. """ model = Book db_session = db.session author_alias = aliased(Author) list_fields = OrderedMultiDict(( ('id', { 'label': 'id', 'column': Book.id }), ('title', { 'label': 'book title', 'column': Book.title }), ('year', { 'label': 'year', 'column': Book.year }), ('author.name', { 'label': 'author name', 'column': author_alias.name }), )) list_title = 'books list' searchable_fields = ['title', 'author.name'] order_by = ('id', 'asc') list_query_factory = model.query\ .outerjoin(author_alias, 'author')\ .options(contains_eager('author', alias=author_alias))\ form_class = BookForm
def custom_form_factory(form, field_types=None, field_slugs=None, excluded_field_types=None, registration_fields=False): fields = (CustomField.query.filter_by(meeting_id=g.meeting.id) .order_by(CustomField.sort)) if field_types: fields = fields.filter(CustomField.field_type.in_(field_types)) if field_slugs: fields = fields.filter(CustomField.slug.in_(field_slugs)) if excluded_field_types: fields = fields.filter( ~CustomField.field_type.in_(excluded_field_types)) if registration_fields: fields = fields.for_registration() if getattr(form, 'CUSTOM_FIELDS_TYPE', None): fields = fields.filter_by(custom_field_type=form.CUSTOM_FIELDS_TYPE) form_attrs = { '_custom_fields': OrderedMultiDict({c.slug: c for c in fields}), } for f in fields: attrs = {'label': unicode(CustomFieldLabel(f.label)), 'validators': [], 'render_kw': {}, 'description': f.hint} data = _CUSTOM_FIELDS_MAP[f.field_type.code] # overwrite data if _CUSTOM_FIELDS_MAP attribute is present on form form_fields_map = getattr(form, '_CUSTOM_FIELDS_MAP', None) if form_fields_map: try: data = form_fields_map[f.field_type.code] except KeyError: pass if f.required: attrs['validators'].append(DataRequired()) attrs['validators'].extend(data.get('validators', [])) if f.max_length: attrs['validators'].append(Length(max=f.max_length)) if f.field_type.code == CustomField.SELECT: query = CustomFieldChoice.query.filter_by(custom_field=f) attrs['choices'] = [(unicode(c.value), __(c.value.english)) for c in query] if not f.required: attrs['choices'] = [('', '---')] + attrs['choices'] if f.slug == 'title': attrs['choices'] = [choice for choice in attrs['choices'] if choice[0] in app.config['TITLE_CHOICES']] attrs['coerce'] = unicode if f.field_type.code == CustomField.LANGUAGE: attrs['choices'] = [i for i in Participant.LANGUAGE_CHOICES if i[0].lower() in app.config['TRANSLATIONS']] if not f.required: attrs['choices'] = [('', '---')] + attrs['choices'] attrs['coerce'] = unicode if f.field_type.code == CustomField.CATEGORY: query = Category.get_categories_for_meeting( form.CUSTOM_FIELDS_TYPE) if registration_fields: query = query.filter_by(visible_on_registration_form=True) attrs['choices'] = [(c.id, c) for c in query] attrs['coerce'] = int if f.field_type.code in (CustomField.MULTI_CHECKBOX, CustomField.RADIO): query = CustomFieldChoice.query.filter_by(custom_field=f) attrs['choices'] = [(unicode(c.value), c.value) for c in query] attrs['coerce'] = unicode if f.field_type.code == CustomField.IMAGE and f.photo_size and f.photo_size.code: attrs['render_kw']["data-photoSize"] = f.photo_size.code for coord in ("x1", "y1", "x2", "y2"): form_attrs['%s_%s_' % (f.slug, coord)] = HiddenField(default=0) # set field to form # _set_rules_for_custom_fields(f, attrs) field = data['field'](**attrs) setattr(field, 'field_type', f.field_type.code) form_attrs[f.slug] = field form_attrs['rules'] = Rule.get_rules_for_fields(fields) return type(form)(form.__name__, (form,), form_attrs)
class Dash(object): """docstring for Dash""" def __init__(self, app, url_prefix='/dashboard', title='dashboard', endpoint='dash'): self.app = app self.blueprint = Blueprint(endpoint, __name__, static_folder='static', template_folder='templates',) self.url_prefix = url_prefix self.title = title self._register_model = OrderedMultiDict() self._panels = OrderedMultiDict() def register_model(self, model, db_session, list_fields=None, model_class=DashModelView,): if not hasattr(model, '__modelclass__'): model = model_class(model, db_session,self.blueprint.name) if list_fields: model.list_fields = list_fields self._register_model[model] = model def register_panel(self, title, panel): panel = panel(self, title) self._panels[title] = panel def get_panels(self): return sorted(self._panels.values(), key=lambda x: x.title) def get_url_name(self,model,name): if self._register_model.has_key(model): model = self._register_model[model] return '%s.%s_%s' % (self.blueprint.name,model.model_name, name,) def index(self): return 'ss' def get_urls(self): return ( ('/', self.index), ) def register_jinja_filter(self): self.app.jinja_env.filters['get_field_attr'] = get_field_attr def register_blueprint(self, **kwargs): self.app.register_blueprint( self.blueprint, url_prefix=self.url_prefix, **kwargs) def configure_routes(self): for url, func in self.get_urls(): self.blueprint.route(url, methods=['GET', 'POST'])(func) for model in self._register_model.values(): model_name = model.model_name() for url, func in model.get_urls(): full_url = '/%s%s' % (model_name.lower(), url) self.blueprint.add_url_rule( full_url, "%s_%s" % (model_name.lower(), func.__name__), func, methods=['GET', 'POST'], ) for panel in self._panels.values(): for url, func in panel.get_urls(): full_url = '/%s%s' % (panel.title, url) self.blueprint.add_url_rule( full_url, "panel_%s_%s" % (panel.title, func.__name__), func, ) def setup(self): self.configure_routes() self.register_blueprint() self.register_jinja_filter()
class Admin(object): """Class that provides a way to add admin interface to Flask applications. :param app: The Flask application :param url_prefix: The url prefix :param main_dashboard: The main dashboard object :param endpoint: The endpoint """ def __init__(self, app, url_prefix="/admin", title="flask-dashed", main_dashboard=None, endpoint='admin'): if not main_dashboard: from dashboard import DefaultDashboard main_dashboard = DefaultDashboard self.blueprint = Blueprint(endpoint, __name__, static_folder='static', template_folder='templates') self.app = app self.url_prefix = url_prefix self.endpoint = endpoint self.title = title self.secure_functions = OrderedMultiDict() # Checks security for current path self.blueprint.before_request( lambda: self.check_path_security(request.path)) self.app.register_blueprint(self.blueprint, url_prefix=url_prefix) self.root_nodes = [] self._add_node(main_dashboard, '/', 'main-dashboard', 'dashboard') # Registers recursive_getattr filter self.app.jinja_env.filters['recursive_getattr'] = recursive_getattr def register_node(self, url_prefix, endpoint, short_title, title=None, parent=None, node_class=AdminNode): """Registers admin node. :param url_prefix: The url prefix :param endpoint: The endpoint :param short_title: The short title :param title: The long title :param parent: The parent node path :param node_class: The class for node objects """ return self._add_node(node_class, url_prefix, endpoint, short_title, title=title, parent=parent) def register_module(self, module_class, url_prefix, endpoint, short_title, title=None, parent=None): """Registers new module to current admin. """ return self._add_node(module_class, url_prefix, endpoint, short_title, title=title, parent=parent) def _add_node(self, node_class, url_prefix, endpoint, short_title, title=None, parent=None): """Registers new node object to current admin object. """ title = short_title if not title else title if parent and not issubclass(parent.__class__, AdminNode): raise Exception('`parent` class must be AdminNode subclass') new_node = node_class(self, url_prefix, endpoint, short_title, title=title, parent=parent) if parent: parent.children.append(new_node) else: self.root_nodes.append(new_node) return new_node @property def main_dashboard(self): return self.root_nodes[0] def add_path_security(self, path, function, http_code=403): """Registers security function for given path. :param path: The endpoint to secure :param function: The security function :param http_code: The response http code """ self.secure_functions.add(path, (function, http_code)) def check_path_security(self, path): """Checks security for specific and path. :param path: The path to check """ for key in self.secure_functions.iterkeys(): if path.startswith("%s%s" % (self.url_prefix, key)): for function, http_code in self.secure_functions.getlist(key): if not function(): return abort(http_code)
def __init__(self, *args, **kwargs): super(AdminModule, self).__init__(*args, **kwargs) self.rules = OrderedMultiDict() self._register_rules()
class AdminModule(AdminNode): """Class that provides a way to create simple admin module. :param admin: The parent admin object :param url_prefix: The url prefix :param enpoint: The endpoint :param short_title: the short module title use on navigation & breadcrumbs :param title: The long title :param parent: The parent node """ def __init__(self, *args, **kwargs): super(AdminModule, self).__init__(*args, **kwargs) self.rules = OrderedMultiDict() self._register_rules() def add_url_rule(self, rule, endpoint, view_func, **options): """Adds a routing rule to the application from relative endpoint. `view_class` is copied as we need to dynamically apply decorators. :param rule: The rule :param endpoint: The endpoint :param view_func: The view """ class ViewClass(view_func.view_class): pass ViewClass.__name__ = "%s_%s" % (self.endpoint, endpoint) ViewClass.__module__ = view_func.__module__ view_func.view_class = ViewClass full_endpoint = "%s.%s_%s" % (self.admin.endpoint, self.endpoint, endpoint) self.admin.app.add_url_rule("%s%s%s" % (self.admin.url_prefix, self.url_path, rule), full_endpoint, view_func, **options) self.rules.setlist(endpoint, [(rule, endpoint, view_func)]) def _register_rules(self): """Registers all module rules after initialization. """ if not hasattr(self, 'default_rules'): raise NotImplementedError('Admin module class must provide' + ' default_rules') for rule, endpoint, view_func in self.default_rules: self.add_url_rule(rule, endpoint, view_func) @property def url(self): """Returns first registered (main) rule as url. """ try: return url_for("%s.%s_%s" % (self.admin.endpoint, self.endpoint, self.rules.lists()[0][0])) # Cause OrderedMultiDict.keys() doesn't preserve order... except IndexError: raise Exception('`AdminModule` must provide at list one rule.') def secure_endpoint(self, endpoint, http_code=403): """Gives a way to secure specific url path. :param endpoint: The endpoint to protect :param http_code: The response http code when False """ def decorator(f): self._secure_enpoint(endpoint, f, http_code) return f return decorator def _secure_enpoint(self, endpoint, secure_function, http_code): """Secure enpoint view function via `secure` decorator. :param enpoint: The endpoint to secure :param secure_function: The function to check :param http_code: The response http code when False. """ rule, endpoint, view_func = self.rules.get(endpoint) view_func.view_class.dispatch_request =\ secure(endpoint, secure_function, http_code)( view_func.view_class.dispatch_request)
def get_columns(self): columns = OrderedMultiDict() for column in self.model.__table__.columns: columns[column.name] = getattr(self.model, column.name) self.column_names = columns.keys() return columns