--- /dev/null
+# -*- 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.
+"""
+
+ GRUF3 Feature-preview stuff.
+
+ This code shouldn't be here but allow people to preview advanced GRUF3
+ features (eg. flexible LDAP searching in 'sharing' tab, ...) in Plone 2,
+ without having to upgrade to Plone 2.1.
+
+ Methods here are monkey-patched by now but will be provided directly by
+ Plone 2.1.
+ Please forgive this 'uglyness' but some users really want to have full
+ LDAP support without switching to the latest Plone version ! ;)
+
+
+ BY DEFAULT, this thing IS enabled with Plone 2.0.x
+"""
+__version__ = "$Revision: $"
+# $Source: $
+# $Id: PloneFeaturePreview.py 587 2008-07-31 09:20:06Z pin $
+__docformat__ = 'restructuredtext'
+
+from Products.CMFCore.utils import UniqueObject
+from Products.CMFCore.utils import getToolByName
+from OFS.SimpleItem import SimpleItem
+from OFS.Image import Image
+from Globals import InitializeClass, DTMLFile, MessageDialog
+from Acquisition import aq_base
+from AccessControl.User import nobody
+from AccessControl import ClassSecurityInfo
+from Products.CMFCore.ActionProviderBase import ActionProviderBase
+from interfaces.portal_groups import portal_groups as IGroupsTool
+from global_symbols import *
+
+
+# This is "stollen" from MembershipTool.py
+# this should probably be in MemberDataTool.py
+def searchForMembers( self, REQUEST=None, **kw ):
+ """
+ searchForMembers(self, REQUEST=None, **kw) => normal or fast search method.
+
+ The following properties can be provided:
+ - name
+ - email
+ - last_login_time
+ - roles
+
+ This is an 'AND' request.
+
+ If name is provided, then a _fast_ search is performed with GRUF's
+ searchUsersByName() method. This will improve performance.
+
+ In any other case, a regular (possibly _slow_) search is performed.
+ As it uses the listMembers() method, which is itself based on gruf.getUsers(),
+ this can return partial results. This may change in the future.
+ """
+ md = self.portal_memberdata
+ mt = self.portal_membership
+ if REQUEST:
+ dict = REQUEST
+ else:
+ dict = kw
+
+ # Attributes retreiving & mangling
+ name = dict.get('name', None)
+ email = dict.get('email', None)
+ roles = dict.get('roles', None)
+ last_login_time = dict.get('last_login_time', None)
+ is_manager = mt.checkPermission('Manage portal', self)
+ if name:
+ name = name.strip().lower()
+ if email:
+ email = email.strip().lower()
+
+
+ # We want 'name' request to be handled properly with large user folders.
+ # So we have to check both the fullname and loginname, without scanning all
+ # possible users.
+ md_users = None
+ uf_users = None
+ if name:
+ # We first find in MemberDataTool users whose _full_ name match what we want.
+ lst = md.searchMemberDataContents('fullname', name)
+ md_users = [ x['username'] for x in lst ]
+
+ # Fast search management if the underlying acl_users support it.
+ # This will allow us to retreive users by their _id_ (not name).
+ acl_users = self.acl_users
+ meth = getattr(acl_users, "searchUsersByName", None)
+ if meth:
+ uf_users = meth(name) # gruf search
+
+ # Now we have to merge both lists to get a nice users set.
+ # This is possible only if both lists are filled (or we may miss users else).
+ Log(LOG_DEBUG, md_users, uf_users, )
+ members = []
+ if md_users is not None and uf_users is not None:
+ names_checked = 1
+ wrap = mt.wrapUser
+ getUser = acl_users.getUser
+ for userid in md_users:
+ members.append(wrap(getUser(userid)))
+ for userid in uf_users:
+ if userid in md_users:
+ continue # Kill dupes
+ usr = getUser(userid)
+ if usr is not None:
+ members.append(wrap(usr))
+
+ # Optimization trick
+ if not email and \
+ not roles and \
+ not last_login_time:
+ return members
+ else:
+ # If the lists are not available, we just stupidly get the members list
+ members = self.listMembers()
+ names_checked = 0
+
+ # Now perform individual checks on each user
+ res = []
+ portal = self.portal_url.getPortalObject()
+
+ for member in members:
+ #user = md.wrapUser(u)
+ u = member.getUser()
+ if not (member.listed or is_manager):
+ continue
+ if name and not names_checked:
+ if (u.getUserName().lower().find(name) == -1 and
+ member.getProperty('fullname').lower().find(name) == -1):
+ continue
+ if email:
+ if member.getProperty('email').lower().find(email) == -1:
+ continue
+ if roles:
+ user_roles = member.getRoles()
+ found = 0
+ for r in roles:
+ if r in user_roles:
+ found = 1
+ break
+ if not found:
+ continue
+ if last_login_time:
+ if member.last_login_time < last_login_time:
+ continue
+ res.append(member)
+ Log(LOG_DEBUG, res)
+ return res
+
+
+def listAllowedMembers(self,):
+ """listAllowedMembers => list only members which belong
+ to the same groups/roles as the calling user.
+ """
+ user = self.REQUEST['AUTHENTICATED_USER']
+ caller_roles = user.getRoles() # Have to provide a hook for admins
+ current_members = self.listMembers()
+ allowed_members =[]
+ for member in current_members:
+ for role in caller_roles:
+ if role in member.getRoles():
+ allowed_members.append(member)
+ break
+ return allowed_members
+
+
+def _getPortrait(self, member_id):
+ """
+ return member_id's portrait if you can.
+ If it's not possible, just try to fetch a 'portait' property from the underlying user source,
+ then create a portrait from it.
+ """
+ # fetch the 'portrait' property
+ Log(LOG_DEBUG, "trying to fetch the portrait for the given member id")
+ portrait = self._former_getPortrait(member_id)
+ if portrait:
+ Log(LOG_DEBUG, "Returning the old-style portrait:", portrait, "for", member_id)
+ return portrait
+
+ # Try to find a portrait in the user source
+ member = self.portal_membership.getMemberById(member_id)
+ portrait = member.getUser().getProperty('portrait', None)
+ if not portrait:
+ Log(LOG_DEBUG, "No portrait available in the user source for", member_id)
+ return None
+
+ # Convert the user-source portrait into a plone-complyant one
+ Log(LOG_DEBUG, "Converting the portrait", type(portrait))
+ portrait = Image(id=member_id, file=portrait, title='')
+ membertool = self.portal_memberdata
+ membertool._setPortrait(portrait, member_id)
+
+ # Re-call ourself to retreive the real portrait
+ Log(LOG_DEBUG, "Returning the real portrait")
+ return self._former_getPortrait(member_id)
+
+
+def setLocalRoles( self, obj, member_ids, member_role, reindex=1 ):
+ """ Set local roles on an item """
+ member = self.getAuthenticatedMember()
+ gruf = self.acl_users
+ my_roles = member.getRolesInContext( obj )
+
+ if 'Manager' in my_roles or member_role in my_roles:
+ for member_id in member_ids:
+ u = gruf.getUserById(member_id) or gruf.getGroupByName(member_id)
+ if not u:
+ continue
+ member_id = u.getUserId()
+ roles = list(obj.get_local_roles_for_userid( userid=member_id ))
+
+ if member_role not in roles:
+ roles.append( member_role )
+ obj.manage_setLocalRoles( member_id, roles )
+
+ if reindex:
+ # It is assumed that all objects have the method
+ # reindexObjectSecurity, which is in CMFCatalogAware and
+ # thus PortalContent and PortalFolder.
+ obj.reindexObjectSecurity()
+
+def deleteLocalRoles( self, obj, member_ids, reindex=1 ):
+ """ Delete local roles for members member_ids """
+ member = self.getAuthenticatedMember()
+ my_roles = member.getRolesInContext( obj )
+ gruf = self.acl_users
+ member_ids = [
+ u.getUserId() for u in [
+ gruf.getUserById(u) or gruf.getGroupByName(u) for u in member_ids
+ ] if u
+ ]
+
+ if 'Manager' in my_roles or 'Owner' in my_roles:
+ obj.manage_delLocalRoles( userids=member_ids )
+
+ if reindex:
+ obj.reindexObjectSecurity()
+
+# Monkeypatch it !
+if PREVIEW_PLONE21_IN_PLONE20_:
+ from Products.CMFCore import MembershipTool as CMFCoreMembershipTool
+ CMFCoreMembershipTool.MembershipTool.setLocalRoles = setLocalRoles
+ CMFCoreMembershipTool.MembershipTool.deleteLocalRoles = deleteLocalRoles
+ from Products.CMFPlone import MemberDataTool
+ from Products.CMFPlone import MembershipTool
+ MembershipTool.MembershipTool.searchForMembers = searchForMembers
+ MembershipTool.MembershipTool.listAllowedMembers = listAllowedMembers
+ MemberDataTool.MemberDataTool._former_getPortrait = MemberDataTool.MemberDataTool._getPortrait
+ MemberDataTool.MemberDataTool._getPortrait = _getPortrait
+ Log(LOG_NOTICE, "Applied GRUF's monkeypatch over Plone 2.0.x. Enjoy!")
+
+
+