text: from collections import OrderedDict
  from operator import or_
  
  from django.conf.urls import url
  from django.conf.urls import include
  from django.contrib.admin.sites import AdminSite
  
  from baya.permissions import requires
  from baya.membership import ValueNode
  from functools import reduce
  
  
  # Keep a registry of baya-enabled admin sites so we can properly intercept
  # permissions checking in NestedLDAPGroupsBackend.
  _admin_registry = set()
  
  
  class NestedGroupsAdminSite(AdminSite):
      def __init__(self, *args, **kwargs):
          super(NestedGroupsAdminSite, self).__init__(*args, **kwargs)
          _admin_registry.add(self)
          all_groups = self._get_required_baya_groups()
          if all_groups is not None:
              self.index = requires(all_groups)(self.index)
              self.app_index = requires(all_groups)(self.app_index)
  
      def _get_admins_with_gate(self):
          admins = []
          # Only need to sort this list so we get consistent OperatorNode trees.
          items = sorted(self._registry.items(),
                         key=lambda x: x[0]._meta.model_name)
          for model, model_admin in items:
              if hasattr(model_admin, '_gate'):
                  admins.append((model, model_admin))
          return admins
  
      def get_urls(self):
          """Ensure that urls included in get_urls() are behind requires().
  
          We need to fix the include() logic for admin URLs. Django admin isn't
          very extensible, so we have to call super, remove the url patterns
          for model_admins that have a _gate, and replace the pattern with
          a properly built include behind the model admin's gate.
  
          Would be a lot easier if django exposed something like
          get_patterns_for_app(app_label), but noooooo.
          """
          # We have to maintain the URL ordering due to the way URLs are resolved
          # TODO - Test this, can lead to heisenbugs
          urls = OrderedDict((urlp.regex.pattern, urlp) for urlp in
                             super(NestedGroupsAdminSite, self).get_urls())
          for model, model_admin in self._get_admins_with_gate():
              if hasattr(model._meta, 'module_name'):
                  model_name = model._meta.module_name
              elif hasattr(model._meta, 'model_name'):
                  model_name = model._meta.model_name
              else:
                  raise ValueError(
                      "Model Admin is missing a module or model name.")
              pattern = (
                  r'^%s/%s/' %
                  (model._meta.app_label, model_name))
              urls[pattern] = url(
                  pattern,
                  requires(get=model_admin._gate.get_requires,
                           post=model_admin._gate.post_requires)(
                               include(model_admin.urls)))
          return list(urls.values())
  
      def _get_required_baya_groups(self, app_label=None):
          # Loop over all model admins, checking their set of permissions
          all_roles = OrderedDict()
          for model, model_admin in self._get_admins_with_gate():
              if app_label and app_label != model._meta.app_label:
                  continue
              roles = model_admin._gate.get_requires
              if roles is not None and not isinstance(roles, ValueNode):
                  all_roles[roles] = True
          if all_roles:
              return reduce(or_, all_roles.keys())
          return None
  
      def admin_view(self, view, cacheable=False):
          fn = super(NestedGroupsAdminSite, self).admin_view(view, cacheable)
          all_groups = self._get_required_baya_groups()
          if all_groups is not None:
              fn = requires(all_groups)(fn)
          return fn
  