-# -*- coding: utf-8 -*-
-## GroupUserFolder
-## Copyright (C)2006 Ingeniweb
-
-## This program is free software; you can redistribute it and/or modify
-## it under the terms of the GNU General Public License as published by
-## the Free Software Foundation; either version 2 of the License, or
-## (at your option) any later version.
-
-## This program is distributed in the hope that it will be useful,
-## but WITHOUT ANY WARRANTY; without even the implied warranty of
-## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-## GNU General Public License for more details.
-
-## You should have received a copy of the GNU General Public License
-## along with this program; see the file COPYING. If not, write to the
-## Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-## Copyright (c) 2003 The Connexions Project, All Rights Reserved
-## initially written by J Cameron Cooper, 11 June 2003
-## concept with Brent Hendricks, George Runyan
-"""
-Basic group data tool.
-"""
-__version__ = "$Revision: $"
-# $Source: $
-# $Id: GroupDataTool.py 52136 2007-10-21 20:38:00Z encolpe $
-__docformat__ = 'restructuredtext'
-
-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, Permissions, Unauthorized, getSecurityManager
-from zope.interface import implements
-from Products.CMFCore.interfaces import IActionProvider
-
-from Products.CMFCore.ActionProviderBase import ActionProviderBase
-
-# BBB CMF < 1.5
-try:
- from Products.CMFCore.permissions import ManagePortal
-except ImportError:
- from Products.CMFCore.CMFCorePermissions import ManagePortal
-
-# from Products.CMFCore.MemberDataTool import CleanupTemp
-
-from interfaces.portal_groupdata import portal_groupdata as IGroupDataTool
-from interfaces.portal_groupdata import GroupData as IGroupData
-from Products.GroupUserFolder import postonly
-from Products.GroupUserFolder.GRUFUser import GRUFGroup
-
-_marker = [] # Create a new marker object.
-
-from global_symbols import *
-
-
-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
- implements(IGroupDataTool, IActionProvider)
- # __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'
- },
- )
- + PropertyManager.manage_options
- + SimpleItem.manage_options
- )
-
- #
- # ZMI methods
- #
- security.declareProtected(ManagePortal, 'manage_overview')
- manage_overview = DTMLFile('dtml/explainGroupDataTool', 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')
- 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}
-# XXX ClenupTemp doesn't exits
-# if hasattr(self, 'REQUEST'):
-# # No REQUEST during tests.
-# 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')
- 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())
-
-
- security.declarePrivate("canAdministrateGroup")
- def canAdministrateGroup(self,):
- """
- Return true if the #current# user can administrate this group
- """
- user = getSecurityManager().getUser()
- tool = self.getTool()
- portal = getToolByName(tool, 'portal_url').getPortalObject()
-
- # Has manager users pemission?
- if user.has_permission(Permissions.manage_users, portal):
- return True
-
- # Is explicitly mentioned as a group administrator?
- managers = self.getProperty('delegated_group_member_managers', ())
- if user.getId() in managers:
- return True
-
- # Belongs to a group which is explicitly mentionned as a group administrator
- meth = getattr(user, "getAllGroupNames", None)
- if meth:
- groups = meth()
- else:
- groups = ()
- for v in groups:
- if v in managers:
- return True
-
- # No right to edit this: we complain.
- return False
-
- security.declarePublic('addMember')
- def addMember(self, id, REQUEST=None):
- """ Add the existing member with the given id to the group"""
- # We check if the current user can directly or indirectly administrate this group
- if not self.canAdministrateGroup():
- raise Unauthorized, "You cannot add a member to the group."
- self._getGroup().addMember(id)
-
- # Notify member that they've been changed
- mtool = getToolByName(self, 'portal_membership')
- member = mtool.getMemberById(id)
- if member:
- member.notifyModified()
- addMember = postonly(addMember)
-
- security.declarePublic('removeMember')
- def removeMember(self, id, REQUEST=None):
- """Remove the member with the provided id from the group.
- """
- # We check if the current user can directly or indirectly administrate this group
- if not self.canAdministrateGroup():
- raise Unauthorized, "You cannot remove a member from the group."
- self._getGroup().removeMember(id)
-
- # Notify member that they've been changed
- mtool = getToolByName(self, 'portal_membership')
- member = mtool.getMemberById(id)
- if member:
- member.notifyModified()
- removeMember = postonly(removeMember)
-
- 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( aq_base(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."""
- if isinstance(self, GRUFGroup):
- return self.getGroup().getId(unprefixed = 1)
- else:
- return self.getGroup().getId()
-
- def getGroupTitleOrName(self):
- """Get the Title property of the group. If there is none
- then return the name """
- title = self.getProperty('title', None)
- return title or self.getGroupName()
-
- 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)