Logo Search packages:      
Sourcecode: zope-groupuserfolder version File versions

GroupDataTool.py

##############################################################################
#
# Copyright (c) 2003 The Connexions Project and Contributors. All Rights Reserved.
#
##############################################################################
""" Basic group data tool.

$Id: GroupDataTool.py,v 1.20 2004/06/09 14:01:49 pjgrizel Exp $
"""

from Products.CMFCore.utils import UniqueObject, getToolByName
from OFS.SimpleItem import SimpleItem
from OFS.PropertyManager import PropertyManager
from Globals import DTMLFile
from Globals import InitializeClass
from AccessControl.Role import RoleManager
from BTrees.OOBTree import OOBTree
from ZPublisher.Converters import type_converters
from Acquisition import aq_inner, aq_parent, aq_base
from AccessControl import ClassSecurityInfo
from Products.CMFCore.CMFCorePermissions import ViewManagementScreens
from Products.CMFCore.CMFCorePermissions import ManagePortal
from Products.CMFCore.CMFCorePermissions import SetOwnProperties
from Products.CMFCore.ActionProviderBase import ActionProviderBase
from AccessControl import Permissions

# Try/except around this to avoid import errors on Plone 1.0.3
# XXX jcc => can you check this, please ?
try:
    from Products.CMFCore.MemberDataTool import CleanupTemp
    _have_cleanup_temp = 1
except:
    _have_cleanup_temp = None

from interfaces.portal_groupdata import portal_groupdata as IGroupDataTool
from interfaces.portal_groupdata import GroupData as IGroupData

_marker = []  # Create a new marker object.

from global_symbols import *



00044 class GroupDataTool (UniqueObject, SimpleItem, PropertyManager, ActionProviderBase):
    """ This tool wraps group objects, allowing transparent access to properties.
    """
    # The latter will work only with Plone 1.1 => hence, the if
    if hasattr(ActionProviderBase, '__implements__'):
        __implements__ = (IGroupDataTool, ActionProviderBase.__implements__)

    id = 'portal_groupdata'
    meta_type = 'CMF Group Data Tool'
    _actions = ()

    _v_temps = None
    _properties=({'id':'title', 'type': 'string', 'mode': 'wd'},)

    security = ClassSecurityInfo()

    manage_options=( ActionProviderBase.manage_options +
                     ({ 'label' : 'Overview'
                       , 'action' : 'manage_overview'
                       },
#                     , { 'label' : 'Contents'
#                       , 'action' : 'manage_showContents'
#                       }
                     )
                   + PropertyManager.manage_options
                   + SimpleItem.manage_options
                   )

    #
    #   ZMI methods
    #
    security.declareProtected(ManagePortal, 'manage_overview')
    manage_overview = DTMLFile('dtml/explainGroupDataTool', globals())

    #security.declareProtected(ViewManagementScreens, 'manage_showContents')
    #manage_showContents = DTMLFile('dtml/groupdataContents', globals())


    def __init__(self):
        self._members = OOBTree()
        # Create the default properties.
        self._setProperty('description', '', 'text')
        self._setProperty('email', '', 'string')

    #
    #   'portal_groupdata' interface methods
    #
    security.declarePrivate('wrapGroup')
00092     def wrapGroup(self, g):
        """Returns an object implementing the GroupData interface"""
        id = g.getId()
        members = self._members
        if not members.has_key(id):
            # Get a temporary member that might be
            # registered later via registerMemberData().
            temps = self._v_temps
            if temps is not None and temps.has_key(id):
                portal_group = temps[id]
            else:
                base = aq_base(self)
                portal_group = GroupData(base, id)
                if temps is None:
                    self._v_temps = {id:portal_group}
                    if hasattr(self, 'REQUEST'):
                        # No REQUEST during tests.
                        # XXX jcc => CleanupTemp doesn't seem to work on Plone 1.0.3.
                        # Have to find a way to pass around...
                        if _have_cleanup_temp:
                            self.REQUEST._hold(CleanupTemp(self))
                else:
                    temps[id] = portal_group
        else:
            portal_group = members[id]
        # Return a wrapper with self as containment and
        # the user as context.
        return portal_group.__of__(self).__of__(g)

    security.declarePrivate('registerGroupData')
00122     def registerGroupData(self, g, id):
        '''
        Adds the given member data to the _members dict.
        This is done as late as possible to avoid side effect
        transactions and to reduce the necessary number of
        entries.
        '''
        self._members[id] = aq_base(g)


InitializeClass(GroupDataTool)


class GroupData (SimpleItem):

    __implements__ = IGroupData

    security = ClassSecurityInfo()

    id = None
    _tool = None

    def __init__(self, tool, id):
        self.id = id
        # Make a temporary reference to the tool.
        # The reference will be removed by notifyModified().
        self._tool = tool

    def _getGRUF(self,):
        return self.acl_users

    security.declarePrivate('notifyModified')
    def notifyModified(self):
        # Links self to parent for full persistence.
        tool = getattr(self, '_tool', None)
        if tool is not None:
            del self._tool
            tool.registerGroupData(self, self.getId())

    security.declarePublic('getGroup')
    def getGroup(self):
        """ Returns the actual group implementation. Varies by group
        implementation (GRUF/Nux/et al). In GRUF this is a user object."""
        # The user object is our context, but it's possible for
        # restricted code to strip context while retaining
        # containment.  Therefore we need a simple security check.
        parent = aq_parent(self)
        bcontext = aq_base(parent)
        bcontainer = aq_base(aq_parent(aq_inner(self)))
        if bcontext is bcontainer or not hasattr(bcontext, 'getUserName'):
            raise 'GroupDataError', "Can't find group data"
        # Return the user object, which is our context.
        return parent

    def getTool(self):
        return aq_parent(aq_inner(self))


    security.declarePublic("getGroupMemberIds")
    def getGroupMemberIds(self,):
        """
        Return a list of group member ids
        """
        return map(lambda x: x.getMemberId(), self.getGroupMembers())


    security.declarePublic("getAllGroupMemberIds")
    def getAllGroupMemberIds(self,):
        """
        Return a list of group member ids
        """
        return map(lambda x: x.getMemberId(), self.getAllGroupMembers())

    security.declarePublic('getGroupMembers')
    def getGroupMembers(self, ):
        """
        Returns a list of the portal_memberdata-ish members of the group.
        This doesn't include TRANSITIVE groups/users.
        """
        md = self.portal_memberdata
        gd = self.portal_groupdata
        ret = []
        for u_name in self.getGroup().getMemberIds(transitive = 0, ):
            usr = self._getGRUF().getUserById(u_name)
            if not usr:
                raise AssertionError, "Cannot retreive a user by its id !"
            if usr.isGroup():
                ret.append(gd.wrapGroup(usr))
            else:
                ret.append(md.wrapUser(usr))
        return ret


    security.declarePublic('getAllGroupMembers')
    def getAllGroupMembers(self, ):
        """
        Returns a list of the portal_memberdata-ish members of the group.
        This will include transitive groups / users
        """
        md = self.portal_memberdata
        gd = self.portal_groupdata
        ret = []
        for u_name in self.getGroup().getMemberIds():
            usr = self._getGRUF().getUserById(u_name)
            if not usr:
                raise AssertionError, "Cannot retreive a user by its id !"
            if usr.isGroup():
                ret.append(gd.wrapGroup(usr))
            else:
                ret.append(md.wrapUser(usr))
        return ret


    def _getGroup(self,):
        """
        _getGroup(self,) => Get the underlying group object
        """
        return self._getGRUF().getGroupByName(self.getGroupName())


    # FIXME: What permission should this be?
    security.declarePublic('addMember')
    def addMember(self, id):
        """ Add the existing member with the given id to the group"""
        self._getGroup().addMember(id)


    # FIXME: What permission should this be?
    security.declarePublic('removeMember')
    def removeMember(self, id):
        """Remove the member with the provided id from the group.
        """
        self._getGroup().removeMember(id)

    security.declareProtected(Permissions.manage_users, 'setProperties')
    def setProperties(self, properties=None, **kw):
        '''Allows the manager group to set his/her own properties.
        Accepts either keyword arguments or a mapping for the "properties"
        argument.
        '''
        if properties is None:
            properties = kw
        return self.setGroupProperties(properties)


    security.declareProtected(Permissions.manage_users, 'setGroupProperties')
    def setGroupProperties(self, mapping):
        '''Sets the properties of the member.
        '''
        # Sets the properties given in the MemberDataTool.
        tool = self.getTool()
        for id in tool.propertyIds():
            if mapping.has_key(id):
                if not self.__class__.__dict__.has_key(id):
                    value = mapping[id]
                    if type(value)==type(''):
                        proptype = tool.getPropertyType(id) or 'string'
                        if type_converters.has_key(proptype):
                            value = type_converters[proptype](value)
                    setattr(self, id, value)
                    
        # Hopefully we can later make notifyModified() implicit.
        self.notifyModified()

    security.declarePublic('getProperties')
    def getProperties(self, ):
        """ Return the properties of this group. Properties are as usual in Zope."""
        tool = self.getTool()
        ret = {}
        for pty in tool.propertyIds():
            try:
                ret[pty] = self.getProperty(pty)
            except ValueError:
                # We ignore missing ptys
                continue
        return ret


    security.declarePublic('getProperty')
    def getProperty(self, id, default=_marker):
        """ Returns the value of the property specified by 'id' """
        tool = self.getTool()
        base = aq_base( self )

        # First, check the wrapper (w/o acquisition).
        value = getattr( base, id, _marker )
        if value is not _marker:
            return value

        # Then, check the tool and the user object for a value.
        tool_value = tool.getProperty( id, _marker )
        user_value = getattr( self.getGroup(), id, _marker )

        # If the tool doesn't have the property, use user_value or default
        if tool_value is _marker:
            if user_value is not _marker:
                return user_value
            elif default is not _marker:
                return default
            else:
                raise ValueError, 'The property %s does not exist' % id

        # If the tool has an empty property and we have a user_value, use it
        if not tool_value and user_value is not _marker:
            return user_value

        # Otherwise return the tool value
        return tool_value

    def __str__(self):
        return self.getGroupId()



    security.declarePublic("isGroup")
    def isGroup(self,):
        """
        isGroup(self,) => Return true if this is a group.
        Will always return true for groups.
        As MemberData objects do not support this method, it is quite useless by now.
        So one can use groupstool.isGroup(g) instead to get this information.
        """
        return 1


    ### Group object interface ###

    security.declarePublic('getGroupName')
    def getGroupName(self):
        """Return the name of the group, without any special decorations (like GRUF prefixes.)"""
        return self.getGroup().getName()

    security.declarePublic('getGroupId')
    def getGroupId(self):
        """Get the ID of the group. The ID can be used, at least from
        Python, to get the user from the user's UserDatabase.
        Within Plone, all group ids are UNPREFIXED."""
        return self.getGroup().getId(unprefixed = 1)

    security.declarePublic("getMemberId")
    def getMemberId(self,):
        """This exists only for a basic user/group API compatibility
        """
        return self.getGroupId()

    security.declarePublic('getRoles')
    def getRoles(self):
        """Return the list of roles assigned to a user."""
        return self.getGroup().getRoles()

    security.declarePublic('getRolesInContext')
    def getRolesInContext(self, object):
        """Return the list of roles assigned to the user,  including local
        roles assigned in context of the passed in object."""
        return self.getGroup().getRolesInContext(object)

    security.declarePublic('getDomains')
    def getDomains(self):
        """Return the list of domain restrictions for a user"""
        return self.getGroup().getDomains()

    security.declarePublic('has_role')
    def has_role(self, roles, object=None):
        """Check to see if a user has a given role or roles."""
        return self.getGroup().has_role(roles, object)

    # There are other parts of the interface but they are
    # deprecated for use with CMF applications.

InitializeClass(GroupData)

Generated by  Doxygen 1.6.0   Back to index