Ejemplo n.º 1
0
class Admin(object):
  """
  Flask extension for an admin interface with pluggable admin panels.

  Note: this is quite different that a Django-style admin interface.
  """

  def __init__(self, *panels, **kwargs):
    self.app = None
    self.panels = []
    self._panels_endpoints = {}
    self.nav_paths = {}
    self.breadcrumb_items = {}
    self.setup_blueprint()

    self.nav_root = NavGroup(
      'admin', 'root', title=_l(u'Admin'),
      endpoint=None,
      condition=lambda context: (not current_user.is_anonymous()
                                 and security.has_role(current_user, AdminRole))
    )

    for panel in panels:
      self.register_panel(panel)

    app = kwargs.pop('app', None)
    if app is not None:
      self.init_app(app)

  def init_app(self, app):
    panels = app.config.get('ADMIN_PANELS', ())

    # resolve fully qualified name into an AdminPanel object
    for fqn in panels:
      panel_class = import_string(fqn, silent=True)
      if panel_class is None:
        logger.warning('Could not import panel: "%s"', fqn)
        continue
      if not issubclass(panel_class, AdminPanel):
        logger.error('"%s" is not a %s.AdminPanel, skipping',
                     fqn, AdminPanel.__module__)
        continue

      self.register_panel(panel_class())
      logger.debug('Registered panel "%s"', fqn)

    if not self.panels:
      @self.blueprint.route('', endpoint='no_panel')
      def no_panels_view():
        return "No panels registered"

      self.nav_root.endpoint = 'admin.no_panel'
    else:
      self.nav_root.endpoint = self.nav_root.items[0].endpoint

    self.root_breadcrumb_item = BreadcrumbItem(
      label=self.nav_root.title,
      url=self.nav_root.endpoint,
    )

    app.register_blueprint(self.blueprint)

    with app.app_context():
      actions.register(self.nav_root, *self.nav_root.items)

    self.app = app
    app.extensions['admin'] = self

  def register_panel(self, panel):
    if self.app:
      raise ValueError('Extension already initialized for app, cannot add more'
                       ' panel')

    self.panels.append(panel)
    panel.admin = self
    rule = "/" + panel.id
    endpoint = nav_id = panel.id
    abs_endpoint = 'admin.{}'.format(endpoint)

    if hasattr(panel, 'get'):
      self.blueprint.add_url_rule(rule, endpoint, panel.get)
      self._panels_endpoints[abs_endpoint] = panel
    if hasattr(panel, 'post'):
      post_endpoint= endpoint + "_post"
      self.blueprint.add_url_rule(rule, post_endpoint, panel.post,
                                  methods=['POST'])
      self._panels_endpoints['admin.' + post_endpoint] = panel

    panel.install_additional_rules(
        self.get_panel_url_rule_adder(panel, rule, endpoint))

    nav = NavItem('admin:panel', nav_id,
                  title=panel.label, icon=panel.icon, divider=False,
                  endpoint=abs_endpoint)
    self.nav_root.append(nav)
    self.nav_paths[abs_endpoint] = nav.path
    self.breadcrumb_items[panel] = BreadcrumbItem(
      label=panel.label,
      icon=panel.icon,
      url=Endpoint(abs_endpoint)
    )

  def get_panel_url_rule_adder(self, panel, base_url, base_endpoint):
    extension = self

    def add_url_rule(rule, endpoint=None, view_func=None, *args, **kwargs):
      if not rule:
        # '' is already used for panel get/post
        raise ValueError('Invalid additional url rule: {}'.format(repr(rule)))

      if endpoint is None:
        endpoint = _endpoint_from_view_func(view_func)

      if not endpoint.startswith(base_endpoint):
        endpoint = base_endpoint + '_' + endpoint

      extension._panels_endpoints['admin.' + endpoint] = panel
      return self.blueprint.add_url_rule(
        base_url + rule,
        endpoint=endpoint,
        view_func=view_func,
        *args, **kwargs)
    return add_url_rule

  def setup_blueprint(self):
    self.blueprint = Blueprint("admin", __name__,
                               template_folder='templates',
                               url_prefix='/' + _BP_PREFIX)

    self.blueprint.url_value_preprocessor(self.build_breadcrumbs)
    self.blueprint.url_value_preprocessor(self.panel_preprocess_value)

    @self.blueprint.before_request
    def check_security():
      user = current_user._get_current_object()
      if not security.has_role(user, "admin"):
        raise Forbidden()

  def panel_preprocess_value(self, endpoint, view_args):
    panel = self._panels_endpoints.get(endpoint)
    if panel is not None:
      panel.url_value_preprocess(endpoint, view_args)

  def build_breadcrumbs(self, endpoint, view_args):
    g.breadcrumb.append(self.root_breadcrumb_item)
    g.nav['active'] = self.nav_paths.get(endpoint, self.nav_root.path)
    panel = self._panels_endpoints.get(endpoint)
    if panel:
      endpoint_bc = self.breadcrumb_items.get(panel)
    if endpoint_bc:
      g.breadcrumb.append(endpoint_bc)
Ejemplo n.º 2
0
class Admin(object):
    """
    Flask extension for an admin interface with pluggable admin panels.

    Note: this is quite different that a Django-style admin interface.
    """
    def __init__(self, *panels, **kwargs):
        self.app = None
        self.panels = []
        self._panels_endpoints = {}
        self.nav_paths = {}
        self.breadcrumb_items = {}
        self.setup_blueprint()

        self.nav_root = NavGroup('admin',
                                 'root',
                                 title=_l(u'Admin'),
                                 endpoint=None,
                                 condition=lambda context:
                                 (not current_user.is_anonymous and security.
                                  has_role(current_user, AdminRole)))

        for panel in panels:
            self.register_panel(panel)

        app = kwargs.pop('app', None)
        if app is not None:
            self.init_app(app)

    def init_app(self, app):
        panels = app.config.get('ADMIN_PANELS', ())

        # resolve fully qualified name into an AdminPanel object
        for fqn in panels:
            panel_class = import_string(fqn, silent=True)
            if panel_class is None:
                logger.warning('Could not import panel: "%s"', fqn)
                continue
            if not issubclass(panel_class, AdminPanel):
                logger.error('"%s" is not a %s.AdminPanel, skipping', fqn,
                             AdminPanel.__module__)
                continue

            self.register_panel(panel_class())
            logger.debug('Registered panel "%s"', fqn)

        if not self.panels:

            @self.blueprint.route('', endpoint='no_panel')
            def no_panels_view():
                return "No panels registered"

            self.nav_root.endpoint = 'admin.no_panel'
        else:
            self.nav_root.endpoint = self.nav_root.items[0].endpoint

        self.root_breadcrumb_item = BreadcrumbItem(
            label=self.nav_root.title,
            url=self.nav_root.endpoint,
        )

        app.register_blueprint(self.blueprint)

        with app.app_context():
            actions.register(self.nav_root, *self.nav_root.items)

        self.app = app
        app.extensions['admin'] = self

    def register_panel(self, panel):
        if self.app:
            raise ValueError(
                'Extension already initialized for app, cannot add more'
                ' panel')

        self.panels.append(panel)
        panel.admin = self
        rule = "/" + panel.id
        endpoint = nav_id = panel.id
        abs_endpoint = 'admin.{}'.format(endpoint)

        if hasattr(panel, 'get'):
            self.blueprint.add_url_rule(rule, endpoint, panel.get)
            self._panels_endpoints[abs_endpoint] = panel
        if hasattr(panel, 'post'):
            post_endpoint = endpoint + "_post"
            self.blueprint.add_url_rule(rule,
                                        post_endpoint,
                                        panel.post,
                                        methods=['POST'])
            self._panels_endpoints['admin.' + post_endpoint] = panel

        panel.install_additional_rules(
            self.get_panel_url_rule_adder(panel, rule, endpoint))

        nav = NavItem('admin:panel',
                      nav_id,
                      title=panel.label,
                      icon=panel.icon,
                      divider=False,
                      endpoint=abs_endpoint)
        self.nav_root.append(nav)
        self.nav_paths[abs_endpoint] = nav.path
        self.breadcrumb_items[panel] = BreadcrumbItem(
            label=panel.label, icon=panel.icon, url=Endpoint(abs_endpoint))

    def get_panel_url_rule_adder(self, panel, base_url, base_endpoint):
        extension = self

        def add_url_rule(rule, endpoint=None, view_func=None, *args, **kwargs):
            if not rule:
                # '' is already used for panel get/post
                raise ValueError('Invalid additional url rule: {}'.format(
                    repr(rule)))

            if endpoint is None:
                endpoint = _endpoint_from_view_func(view_func)

            if not endpoint.startswith(base_endpoint):
                endpoint = base_endpoint + '_' + endpoint

            extension._panels_endpoints['admin.' + endpoint] = panel
            return self.blueprint.add_url_rule(base_url + rule,
                                               endpoint=endpoint,
                                               view_func=view_func,
                                               *args,
                                               **kwargs)

        return add_url_rule

    def setup_blueprint(self):
        self.blueprint = Blueprint("admin",
                                   __name__,
                                   template_folder='templates',
                                   url_prefix='/' + _BP_PREFIX)

        self.blueprint.url_value_preprocessor(self.build_breadcrumbs)
        self.blueprint.url_value_preprocessor(self.panel_preprocess_value)

        @self.blueprint.before_request
        def check_security():
            user = current_user._get_current_object()
            if not security.has_role(user, "admin"):
                raise Forbidden()

    def panel_preprocess_value(self, endpoint, view_args):
        panel = self._panels_endpoints.get(endpoint)
        if panel is not None:
            panel.url_value_preprocess(endpoint, view_args)

    def build_breadcrumbs(self, endpoint, view_args):
        g.breadcrumb.append(self.root_breadcrumb_item)
        g.nav['active'] = self.nav_paths.get(endpoint, self.nav_root.path)
        panel = self._panels_endpoints.get(endpoint)
        if panel:
            endpoint_bc = self.breadcrumb_items.get(panel)
        if endpoint_bc:
            g.breadcrumb.append(endpoint_bc)
Ejemplo n.º 3
0
class Admin:
    """Flask extension for an admin interface with pluggable admin panels.

    Note: this is quite different that a Django-style admin interface.
    """

    def __init__(self, *panels: Any, **kwargs: Any) -> None:
        self.app = None
        self.panels: List[AdminPanel] = []
        self._panels_endpoints: Dict[str, AdminPanel] = {}
        self.nav_paths: Dict[str, str] = {}
        self.breadcrumb_items: Dict[AdminPanel, BreadcrumbItem] = {}
        self.setup_blueprint()

        def condition(context: Dict[str, bool]) -> bool:
            return not current_user.is_anonymous and security.has_role(
                # pyre-fixme[6]: Expected `Principal` for 1st param but got
                #  `LocalProxy`.
                current_user,
                AdminRole,
            )

        self.nav_root = NavGroup(
            "admin", "root", title=_l("Admin"), endpoint=None, condition=condition
        )

        for panel in panels:
            self.register_panel(panel)

        app = kwargs.pop("app", None)
        if app is not None:
            self.init_app(app)

    def init_app(self, app: Flask) -> None:
        panels = app.config.get("ADMIN_PANELS", ())

        # resolve fully qualified name into an AdminPanel object
        for fqn in panels:
            panel_class = import_string(fqn, silent=True)
            if panel_class is None:
                logger.warning('Could not import panel: "%s"', fqn)
                continue
            if not issubclass(panel_class, AdminPanel):
                logger.error(
                    '"%s" is not a %s.AdminPanel, skipping', fqn, AdminPanel.__module__
                )
                continue

            self.register_panel(panel_class())
            logger.debug('Registered panel "%s"', fqn)

        if not self.panels:

            @self.blueprint.route("", endpoint="no_panel")
            def no_panels_view():
                return "No panels registered"

            self.nav_root.endpoint = "admin.no_panel"
        else:
            self.nav_root.endpoint = self.nav_root.items[0].endpoint

        self.root_breadcrumb_item = BreadcrumbItem(
            label=self.nav_root.title, url=self.nav_root.endpoint
        )

        app.register_blueprint(self.blueprint)

        with app.app_context():
            actions.register(self.nav_root, *self.nav_root.items)

        self.app = app
        app.extensions["admin"] = self

    def register_panel(self, panel: Any) -> None:
        if self.app:
            raise ValueError(
                "Extension already initialized for app, cannot add more" " panel"
            )

        self.panels.append(panel)
        panel.admin = self
        rule = "/" + panel.id
        endpoint = nav_id = panel.id
        abs_endpoint = f"admin.{endpoint}"

        if hasattr(panel, "get"):
            self.blueprint.add_url_rule(rule, endpoint, panel.get)
            self._panels_endpoints[abs_endpoint] = panel
        if hasattr(panel, "post"):
            post_endpoint = endpoint + "_post"
            self.blueprint.add_url_rule(
                rule, post_endpoint, panel.post, methods=["POST"]
            )
            self._panels_endpoints["admin." + post_endpoint] = panel

        panel.install_additional_rules(
            self.get_panel_url_rule_adder(panel, rule, endpoint)
        )

        nav = NavItem(
            "admin:panel",
            nav_id,
            title=panel.label,
            icon=panel.icon,
            endpoint=abs_endpoint,
        )
        self.nav_root.append(nav)
        self.nav_paths[abs_endpoint] = nav.path
        self.breadcrumb_items[panel] = BreadcrumbItem(
            label=panel.label, icon=panel.icon, url=Endpoint(abs_endpoint)
        )

    def get_panel_url_rule_adder(
        self, panel: Any, base_url: str, base_endpoint: str
    ) -> Callable:
        extension = self

        def add_url_rule(
            rule: str,
            endpoint: Optional[Any] = None,
            view_func: Optional[Callable] = None,
            **kwargs: Any,
        ) -> None:
            if not rule:
                # '' is already used for panel get/post
                raise ValueError(f"Invalid additional url rule: {repr(rule)}")

            if endpoint is None:
                # pyre-fixme[16]: Module `helpers` has no attribute
                #  `_endpoint_from_view_func`.
                endpoint = _endpoint_from_view_func(view_func)

            if not endpoint.startswith(base_endpoint):
                endpoint = base_endpoint + "_" + endpoint

            extension._panels_endpoints["admin." + endpoint] = panel
            self.blueprint.add_url_rule(
                base_url + rule, endpoint=endpoint, view_func=view_func, **kwargs
            )

        return add_url_rule

    def setup_blueprint(self) -> None:
        self.blueprint = Blueprint(
            "admin", __name__, template_folder="templates", url_prefix="/" + _BP_PREFIX
        )

        self.blueprint.url_value_preprocessor(self.build_breadcrumbs)
        self.blueprint.url_value_preprocessor(self.panel_preprocess_value)

        @self.blueprint.before_request
        def check_security() -> None:
            user = unwrap(current_user)
            if not security.has_role(user, "admin"):
                raise Forbidden()

    def panel_preprocess_value(self, endpoint: str, view_args: Dict[Any, Any]) -> None:
        panel = self._panels_endpoints.get(endpoint)
        if panel is not None:
            panel.url_value_preprocess(endpoint, view_args)

    def build_breadcrumbs(self, endpoint: str, view_args: Dict[Any, Any]) -> None:
        g.breadcrumb.append(self.root_breadcrumb_item)
        g.nav["active"] = self.nav_paths.get(endpoint, self.nav_root.path)
        panel = self._panels_endpoints.get(endpoint)
        if panel:
            endpoint_bc = self.breadcrumb_items.get(panel)
            if endpoint_bc:
                g.breadcrumb.append(endpoint_bc)
Ejemplo n.º 4
0
class Admin(object):
  """
  Flask extension for an admin interface with pluggable admin panels.

  Note: this is quite different that a Django-style admin interface.
  """

  def __init__(self, *panels, **kwargs):
    self.app = None
    self.panels = []
    self.breadcrumb_items = {}
    self.setup_blueprint()

    self.nav_root = NavGroup(
      'admin', 'root', title=_l(u'Admin'),
      endpoint=None,
      condition=lambda context: (not current_user.is_anonymous()
                                 and security.has_role(current_user, AdminRole))
    )

    for panel in panels:
      self.register_panel(panel)

    app = kwargs.pop('app', None)
    if app is not None:
      self.init_app(app)

  def init_app(self, app):
    panels = app.config.get('ADMIN_PANELS', ())

    # resolve fully qualified name into an AdminPanel object
    for fqn in panels:
      panel_class = import_string(fqn, silent=True)
      if panel_class is None:
        logger.warning('Could not import panel: "%s"', fqn)
        continue
      if not issubclass(panel_class, AdminPanel):
        logger.error('"%s" is not a %s.AdminPanel, skipping', fqn, AdminPanel.__module__)
        continue

      self.register_panel(panel_class())
      logger.debug('Registered panel "%s"', fqn)

    if not self.panels:
      @self.blueprint.route('', endpoint='no_panel')
      def no_panels_view():
        return "No panels registered"

      self.nav_root.endpoint = 'admin.no_panel'
    else:
      self.nav_root.endpoint = self.nav_root.items[0].endpoint

    self.root_breadcrumb_item = BreadcrumbItem(
      label=self.nav_root.title,
      url=Endpoint(self.nav_root.endpoint[0], **self.nav_root.endpoint[1])
    )

    app.register_blueprint(self.blueprint)

    with app.app_context():
      actions.register(self.nav_root, *self.nav_root.items)

    self.app = app
    app.extensions['admin'] = self

  def register_panel(self, panel):
    if self.app:
      raise ValueError("Extension already initialized for app, cannot add more panel")

    self.panels.append(panel)

    panel.admin = self
    rule = "/" + panel.id
    endpoint = nav_id = panel.id
    abs_endpoint = 'admin.{}'.format(endpoint)

    if hasattr(panel, 'get'):
      self.blueprint.add_url_rule(rule, endpoint, panel.get)
    if hasattr(panel, 'post'):
      endpoint += "_post"
      self.blueprint.add_url_rule(rule, endpoint, panel.post, methods=['POST'])

    nav = NavItem('admin:panel', nav_id,
                  title=panel.label, icon=panel.icon, divider=False,
                  endpoint=abs_endpoint)
    self.nav_root.append(nav)
    self.breadcrumb_items[abs_endpoint] = BreadcrumbItem(
      label=panel.label,
      icon=panel.icon,
      url=Endpoint(abs_endpoint)
    )

  def setup_blueprint(self):
    self.blueprint = Blueprint("admin", __name__,
                               template_folder='templates',
                               url_prefix='/' + _BP_PREFIX)

    self.blueprint.url_value_preprocessor(self.build_breadcrumbs)

    @self.blueprint.before_request
    def check_security():
      user = current_user._get_current_object()
      if not security.has_role(user, "admin"):
        abort(403)

    @self.blueprint.context_processor
    def inject_menu():
      menu = []
      for panel in self.panels:
        endpoint = 'admin.' + panel.id
        active = endpoint == request.endpoint
        entry = {'endpoint': endpoint,
                 'label': panel.label,
                 'url': url_for(endpoint),
                 'active': active}
        menu.append(entry)
      return dict(menu=menu)

  def build_breadcrumbs(self, endpoint, view_args):
    g.breadcrumb.append(self.root_breadcrumb_item)
    endpoint_bc = self.breadcrumb_items.get(endpoint)
    if endpoint_bc:
      g.breadcrumb.append(endpoint_bc)