Back to index

plone3  3.1.7
PloneFeaturePreview.py
Go to the documentation of this file.
00001 # -*- coding: utf-8 -*-
00002 ## GroupUserFolder
00003 ## Copyright (C)2006 Ingeniweb
00004 
00005 ## This program is free software; you can redistribute it and/or modify
00006 ## it under the terms of the GNU General Public License as published by
00007 ## the Free Software Foundation; either version 2 of the License, or
00008 ## (at your option) any later version.
00009 
00010 ## This program is distributed in the hope that it will be useful,
00011 ## but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013 ## GNU General Public License for more details.
00014 
00015 ## You should have received a copy of the GNU General Public License
00016 ## along with this program; see the file COPYING. If not, write to the
00017 ## Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00018 """
00019                                                                            
00020                       GRUF3 Feature-preview stuff.                         
00021                                                                            
00022  This code shouldn't be here but allow people to preview advanced GRUF3    
00023  features (eg. flexible LDAP searching in 'sharing' tab, ...) in Plone 2,  
00024  without having to upgrade to Plone 2.1.
00025                                                                            
00026  Methods here are monkey-patched by now but will be provided directly by
00027  Plone 2.1.
00028  Please forgive this 'uglyness' but some users really want to have full    
00029  LDAP support without switching to the latest Plone version ! ;)
00030 
00031 
00032  BY DEFAULT, this thing IS enabled with Plone 2.0.x
00033 """
00034 __version__ = "$Revision:  $"
00035 # $Source:  $
00036 # $Id: PloneFeaturePreview.py 30098 2006-09-08 12:35:01Z encolpe $
00037 __docformat__ = 'restructuredtext'
00038 
00039 from Products.CMFCore.utils import UniqueObject
00040 from Products.CMFCore.utils import getToolByName
00041 from OFS.SimpleItem import SimpleItem
00042 from OFS.Image import Image
00043 from Globals import InitializeClass, DTMLFile, MessageDialog
00044 from Acquisition import aq_base
00045 from AccessControl.User import nobody
00046 from AccessControl import ClassSecurityInfo
00047 from Products.CMFCore.ActionProviderBase import ActionProviderBase
00048 from interfaces.portal_groups import portal_groups as IGroupsTool
00049 from global_symbols import *
00050 
00051 
00052 # This is "stollen" from MembershipTool.py
00053 # this should probably be in MemberDataTool.py
00054 def searchForMembers( self, REQUEST=None, **kw ):
00055     """
00056     searchForMembers(self, REQUEST=None, **kw) => normal or fast search method.
00057 
00058     The following properties can be provided:
00059     - name
00060     - email
00061     - last_login_time
00062     - roles
00063 
00064     This is an 'AND' request.
00065 
00066     If name is provided, then a _fast_ search is performed with GRUF's
00067     searchUsersByName() method. This will improve performance.
00068 
00069     In any other case, a regular (possibly _slow_) search is performed.
00070     As it uses the listMembers() method, which is itself based on gruf.getUsers(),
00071     this can return partial results. This may change in the future.
00072     """
00073     md = self.portal_memberdata
00074     mt = self.portal_membership
00075     if REQUEST:
00076         dict = REQUEST
00077     else:
00078         dict = kw
00079 
00080     # Attributes retreiving & mangling
00081     name = dict.get('name', None)
00082     email = dict.get('email', None)
00083     roles = dict.get('roles', None)
00084     last_login_time = dict.get('last_login_time', None)
00085     is_manager = mt.checkPermission('Manage portal', self)
00086     if name:
00087         name = name.strip().lower()
00088     if email:
00089         email = email.strip().lower()
00090 
00091 
00092     # We want 'name' request to be handled properly with large user folders.
00093     # So we have to check both the fullname and loginname, without scanning all
00094     # possible users.
00095     md_users = None
00096     uf_users = None
00097     if name:
00098         # We first find in MemberDataTool users whose _full_ name match what we want.
00099         lst = md.searchMemberDataContents('fullname', name)
00100         md_users = [ x['username'] for x in lst ]
00101 
00102         # Fast search management if the underlying acl_users support it.
00103         # This will allow us to retreive users by their _id_ (not name).
00104         acl_users = self.acl_users
00105         meth = getattr(acl_users, "searchUsersByName", None)
00106         if meth:
00107             uf_users = meth(name)           # gruf search
00108 
00109     # Now we have to merge both lists to get a nice users set.
00110     # This is possible only if both lists are filled (or we may miss users else).
00111     Log(LOG_DEBUG, md_users, uf_users, )
00112     members = []
00113     if md_users is not None and uf_users is not None:
00114         names_checked = 1
00115         wrap = mt.wrapUser
00116         getUser = acl_users.getUser
00117         for userid in md_users:
00118             members.append(wrap(getUser(userid)))
00119         for userid in uf_users:
00120             if userid in md_users:
00121                 continue             # Kill dupes
00122             usr = getUser(userid)
00123             if usr is not None:
00124                 members.append(wrap(usr))
00125 
00126         # Optimization trick
00127         if not email and \
00128                not roles and \
00129                not last_login_time:
00130             return members          
00131     else:
00132         # If the lists are not available, we just stupidly get the members list
00133         members = self.listMembers()
00134         names_checked = 0
00135 
00136     # Now perform individual checks on each user
00137     res = []
00138     portal = self.portal_url.getPortalObject()
00139 
00140     for member in members:
00141         #user = md.wrapUser(u)
00142         u = member.getUser()
00143         if not (member.listed or is_manager):
00144             continue
00145         if name and not names_checked:
00146             if (u.getUserName().lower().find(name) == -1 and
00147                 member.getProperty('fullname').lower().find(name) == -1):
00148                 continue
00149         if email:
00150             if member.getProperty('email').lower().find(email) == -1:
00151                 continue
00152         if roles:
00153             user_roles = member.getRoles()
00154             found = 0
00155             for r in roles:
00156                 if r in user_roles:
00157                     found = 1
00158                     break
00159             if not found:
00160                 continue
00161         if last_login_time:
00162             if member.last_login_time < last_login_time:
00163                 continue
00164         res.append(member)
00165     Log(LOG_DEBUG, res)
00166     return res
00167 
00168 
00169 def listAllowedMembers(self,):
00170     """listAllowedMembers => list only members which belong
00171     to the same groups/roles as the calling user.
00172     """
00173     user = self.REQUEST['AUTHENTICATED_USER']
00174     caller_roles = user.getRoles()              # Have to provide a hook for admins
00175     current_members = self.listMembers()
00176     allowed_members =[]
00177     for member in current_members:
00178         for role in caller_roles:
00179             if role in member.getRoles():
00180                 allowed_members.append(member)
00181                 break
00182     return allowed_members
00183 
00184 
00185 def _getPortrait(self, member_id):
00186     """
00187     return member_id's portrait if you can.
00188     If it's not possible, just try to fetch a 'portait' property from the underlying user source,
00189     then create a portrait from it.
00190     """
00191     # fetch the 'portrait' property
00192     Log(LOG_DEBUG, "trying to fetch the portrait for the given member id")
00193     portrait = self._former_getPortrait(member_id)
00194     if portrait:
00195         Log(LOG_DEBUG, "Returning the old-style portrait:", portrait, "for", member_id)
00196         return portrait
00197 
00198     # Try to find a portrait in the user source
00199     member = self.portal_membership.getMemberById(member_id)
00200     portrait = member.getUser().getProperty('portrait', None)
00201     if not portrait:
00202         Log(LOG_DEBUG, "No portrait available in the user source for", member_id)
00203         return None
00204 
00205     # Convert the user-source portrait into a plone-complyant one
00206     Log(LOG_DEBUG, "Converting the portrait", type(portrait))
00207     portrait = Image(id=member_id, file=portrait, title='')
00208     membertool = self.portal_memberdata
00209     membertool._setPortrait(portrait, member_id)
00210 
00211     # Re-call ourself to retreive the real portrait
00212     Log(LOG_DEBUG, "Returning the real portrait")
00213     return self._former_getPortrait(member_id)
00214 
00215 
00216 def setLocalRoles( self, obj, member_ids, member_role, reindex=1 ):
00217     """ Set local roles on an item """
00218     member = self.getAuthenticatedMember()
00219     gruf = self.acl_users
00220     my_roles = member.getRolesInContext( obj )
00221 
00222     if 'Manager' in my_roles or member_role in my_roles:
00223         for member_id in member_ids:
00224             u = gruf.getUserById(member_id) or gruf.getGroupByName(member_id)
00225             if not u:
00226                 continue
00227             member_id = u.getUserId()
00228             roles = list(obj.get_local_roles_for_userid( userid=member_id ))
00229 
00230             if member_role not in roles:
00231                 roles.append( member_role )
00232                 obj.manage_setLocalRoles( member_id, roles )
00233 
00234     if reindex:
00235         # It is assumed that all objects have the method
00236         # reindexObjectSecurity, which is in CMFCatalogAware and
00237         # thus PortalContent and PortalFolder.
00238         obj.reindexObjectSecurity()
00239 
00240 def deleteLocalRoles( self, obj, member_ids, reindex=1 ):
00241     """ Delete local roles for members member_ids """
00242     member = self.getAuthenticatedMember()
00243     my_roles = member.getRolesInContext( obj )
00244     gruf = self.acl_users
00245     member_ids = [
00246         u.getUserId() for u in [
00247             gruf.getUserById(u) or gruf.getGroupByName(u) for u in member_ids
00248             ] if u
00249         ]
00250 
00251     if 'Manager' in my_roles or 'Owner' in my_roles:
00252         obj.manage_delLocalRoles( userids=member_ids )
00253 
00254     if reindex:
00255         obj.reindexObjectSecurity()
00256 
00257 # Monkeypatch it !
00258 if PREVIEW_PLONE21_IN_PLONE20_:
00259     from Products.CMFCore import MembershipTool as CMFCoreMembershipTool
00260     CMFCoreMembershipTool.MembershipTool.setLocalRoles = setLocalRoles
00261     CMFCoreMembershipTool.MembershipTool.deleteLocalRoles = deleteLocalRoles
00262     from Products.CMFPlone import MemberDataTool
00263     from Products.CMFPlone import MembershipTool
00264     MembershipTool.MembershipTool.searchForMembers = searchForMembers
00265     MembershipTool.MembershipTool.listAllowedMembers = listAllowedMembers
00266     MemberDataTool.MemberDataTool._former_getPortrait = MemberDataTool.MemberDataTool._getPortrait
00267     MemberDataTool.MemberDataTool._getPortrait = _getPortrait
00268     Log(LOG_NOTICE, "Applied GRUF's monkeypatch over Plone 2.0.x. Enjoy!")
00269 
00270 
00271