# this is the dirty zope monkey-patching code to add groups support
import AccessControl
from AccessControl.PermissionRole import _what_not_even_god_should_do

old_getRolesInContext = AccessControl.User.BasicUser.getRolesInContext

def hacked_getRolesInContext(self, object):
    name = self.getUserName()
    roles = self.getRoles()
    local = {}
    object = getattr(object, 'aq_inner', object)
    while 1:
        local_roles = getattr(object, '__ac_local_roles__', None)
        if local_roles:
            if callable(local_roles):
                local_roles=local_roles()
            dict=local_roles or {}
            for r in dict.get(name, []):
                local[r] = 1
        groups_mapping = getattr(object, '__ac_local_groups__', None)
        if groups_mapping:
            local.update(groups_mapping.getRoles(self))
        inner = getattr(object, 'aq_inner', object)
        parent = getattr(inner, 'aq_parent', None)
        if parent is not None:
            object = parent
            continue
        if hasattr(object, 'im_self'):
            object=object.im_self
            object=getattr(object, 'aq_inner', object)
            continue
        break
    roles = list(roles) + local.keys()
    return roles

old_allowed = AccessControl.User.BasicUser.allowed

def hacked_allowed(self, object, object_roles=None):
    """Check whether the user has access to object. The user must
    have one of the roles in object_roles to allow access."""  
    if object_roles is _what_not_even_god_should_do: return 0
    
    # Short-circuit the common case of anonymous access.
    if object_roles is None or 'Anonymous' in object_roles:
        return 1
    
    # Provide short-cut access if object is protected by 'Authenticated'
    # role and user is not nobody
    user_name = self.getUserName()
    if 'Authenticated' in object_roles and (
        user_name != 'Anonymous User'):
        return 1
    
    # Check for ancient role data up front, convert if found.
    # This should almost never happen, and should probably be
    # deprecated at some point.
    if 'Shared' in object_roles:
        object_roles = self._shared_roles(object)
        if object_roles is None or 'Anonymous' in object_roles:
            return 1
            
    # Check for a role match with the normal roles given to
    # the user, then with local roles only if necessary. We
    # want to avoid as much overhead as possible.
    user_roles = self.getRoles()
    for role in object_roles:
        if role in user_roles:
            if self._check_context(object):
                return 1
            return None

    # Still have not found a match, so check local roles. We do
    # this manually rather than call getRolesInContext so that
    # we can incur only the overhead required to find a match.
    inner_obj = getattr(object, 'aq_inner', object)
    while 1:
        local_roles = getattr(inner_obj, '__ac_local_roles__', None)
        if local_roles:
            if callable(local_roles):
                local_roles = local_roles()
            dict = local_roles or {}
            local_roles = dict.get(user_name, [])
            for role in object_roles:
                if role in local_roles:
                    if self._check_context(object):
                        return 1
                    return 0
        groups_mapping = getattr(inner_obj, '__ac_local_groups__', None)
        if groups_mapping is not None:
            #group_roles = {}
            group_roles = groups_mapping.getRoles(self)
            for role in object_roles:
                if group_roles.has_key(role):
                    if self._check_context(object):
                        return 1
                    return 0
        inner = getattr(inner_obj, 'aq_inner', inner_obj)
        parent = getattr(inner, 'aq_parent', None)
        if parent is not None:
            inner_obj = parent
            continue
        if hasattr(inner_obj, 'im_self'):
            inner_obj=inner_obj.im_self
            inner_obj=getattr(inner_obj, 'aq_inner', inner_obj)
            continue
        break
    return None

AccessControl.User.BasicUser.getRolesInContext = hacked_getRolesInContext
AccessControl.User.BasicUser.allowed = hacked_allowed

