1 # -*- coding: utf-8 -*-
3 ## Copyright (C)2006 Ingeniweb
5 ## This program is free software; you can redistribute it and/or modify
6 ## it under the terms of the GNU General Public License as published by
7 ## the Free Software Foundation; either version 2 of the License, or
8 ## (at your option) any later version.
10 ## This program is distributed in the hope that it will be useful,
11 ## but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ## GNU General Public License for more details.
15 ## You should have received a copy of the GNU General Public License
16 ## along with this program; see the file COPYING. If not, write to the
17 ## Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 GRUF3 Feature-preview stuff.
22 This code shouldn't be here but allow people to preview advanced GRUF3
23 features (eg. flexible LDAP searching in 'sharing' tab, ...) in Plone 2,
24 without having to upgrade to Plone 2.1.
26 Methods here are monkey-patched by now but will be provided directly by
28 Please forgive this 'uglyness' but some users really want to have full
29 LDAP support without switching to the latest Plone version ! ;)
32 BY DEFAULT, this thing IS enabled with Plone 2.0.x
34 __version__
= "$Revision: $"
36 # $Id: PloneFeaturePreview.py 587 2008-07-31 09:20:06Z pin $
37 __docformat__
= 'restructuredtext'
39 from Products
.CMFCore
.utils
import UniqueObject
40 from Products
.CMFCore
.utils
import getToolByName
41 from OFS
.SimpleItem
import SimpleItem
42 from OFS
.Image
import Image
43 from Globals
import InitializeClass
, DTMLFile
, MessageDialog
44 from Acquisition
import aq_base
45 from AccessControl
.User
import nobody
46 from AccessControl
import ClassSecurityInfo
47 from Products
.CMFCore
.ActionProviderBase
import ActionProviderBase
48 from interfaces
.portal_groups
import portal_groups
as IGroupsTool
49 from global_symbols
import *
52 # This is "stollen" from MembershipTool.py
53 # this should probably be in MemberDataTool.py
54 def searchForMembers( self
, REQUEST
=None, **kw
):
56 searchForMembers(self, REQUEST=None, **kw) => normal or fast search method.
58 The following properties can be provided:
64 This is an 'AND' request.
66 If name is provided, then a _fast_ search is performed with GRUF's
67 searchUsersByName() method. This will improve performance.
69 In any other case, a regular (possibly _slow_) search is performed.
70 As it uses the listMembers() method, which is itself based on gruf.getUsers(),
71 this can return partial results. This may change in the future.
73 md
= self
.portal_memberdata
74 mt
= self
.portal_membership
80 # Attributes retreiving & mangling
81 name
= dict.get('name', None)
82 email
= dict.get('email', None)
83 roles
= dict.get('roles', None)
84 last_login_time
= dict.get('last_login_time', None)
85 is_manager
= mt
.checkPermission('Manage portal', self
)
87 name
= name
.strip().lower()
89 email
= email
.strip().lower()
92 # We want 'name' request to be handled properly with large user folders.
93 # So we have to check both the fullname and loginname, without scanning all
98 # We first find in MemberDataTool users whose _full_ name match what we want.
99 lst
= md
.searchMemberDataContents('fullname', name
)
100 md_users
= [ x
['username'] for x
in lst
]
102 # Fast search management if the underlying acl_users support it.
103 # This will allow us to retreive users by their _id_ (not name).
104 acl_users
= self
.acl_users
105 meth
= getattr(acl_users
, "searchUsersByName", None)
107 uf_users
= meth(name
) # gruf search
109 # Now we have to merge both lists to get a nice users set.
110 # This is possible only if both lists are filled (or we may miss users else).
111 Log(LOG_DEBUG
, md_users
, uf_users
, )
113 if md_users
is not None and uf_users
is not None:
116 getUser
= acl_users
.getUser
117 for userid
in md_users
:
118 members
.append(wrap(getUser(userid
)))
119 for userid
in uf_users
:
120 if userid
in md_users
:
121 continue # Kill dupes
122 usr
= getUser(userid
)
124 members
.append(wrap(usr
))
132 # If the lists are not available, we just stupidly get the members list
133 members
= self
.listMembers()
136 # Now perform individual checks on each user
138 portal
= self
.portal_url
.getPortalObject()
140 for member
in members
:
141 #user = md.wrapUser(u)
143 if not (member
.listed
or is_manager
):
145 if name
and not names_checked
:
146 if (u
.getUserName().lower().find(name
) == -1 and
147 member
.getProperty('fullname').lower().find(name
) == -1):
150 if member
.getProperty('email').lower().find(email
) == -1:
153 user_roles
= member
.getRoles()
162 if member
.last_login_time
< last_login_time
:
169 def listAllowedMembers(self
,):
170 """listAllowedMembers => list only members which belong
171 to the same groups/roles as the calling user.
173 user
= self
.REQUEST
['AUTHENTICATED_USER']
174 caller_roles
= user
.getRoles() # Have to provide a hook for admins
175 current_members
= self
.listMembers()
177 for member
in current_members
:
178 for role
in caller_roles
:
179 if role
in member
.getRoles():
180 allowed_members
.append(member
)
182 return allowed_members
185 def _getPortrait(self
, member_id
):
187 return member_id's portrait if you can.
188 If it's not possible, just try to fetch a 'portait' property from the underlying user source,
189 then create a portrait from it.
191 # fetch the 'portrait' property
192 Log(LOG_DEBUG
, "trying to fetch the portrait for the given member id")
193 portrait
= self
._former
_getPortrait
(member_id
)
195 Log(LOG_DEBUG
, "Returning the old-style portrait:", portrait
, "for", member_id
)
198 # Try to find a portrait in the user source
199 member
= self
.portal_membership
.getMemberById(member_id
)
200 portrait
= member
.getUser().getProperty('portrait', None)
202 Log(LOG_DEBUG
, "No portrait available in the user source for", member_id
)
205 # Convert the user-source portrait into a plone-complyant one
206 Log(LOG_DEBUG
, "Converting the portrait", type(portrait
))
207 portrait
= Image(id=member_id
, file=portrait
, title
='')
208 membertool
= self
.portal_memberdata
209 membertool
._setPortrait
(portrait
, member_id
)
211 # Re-call ourself to retreive the real portrait
212 Log(LOG_DEBUG
, "Returning the real portrait")
213 return self
._former
_getPortrait
(member_id
)
216 def setLocalRoles( self
, obj
, member_ids
, member_role
, reindex
=1 ):
217 """ Set local roles on an item """
218 member
= self
.getAuthenticatedMember()
219 gruf
= self
.acl_users
220 my_roles
= member
.getRolesInContext( obj
)
222 if 'Manager' in my_roles
or member_role
in my_roles
:
223 for member_id
in member_ids
:
224 u
= gruf
.getUserById(member_id
) or gruf
.getGroupByName(member_id
)
227 member_id
= u
.getUserId()
228 roles
= list(obj
.get_local_roles_for_userid( userid
=member_id
))
230 if member_role
not in roles
:
231 roles
.append( member_role
)
232 obj
.manage_setLocalRoles( member_id
, roles
)
235 # It is assumed that all objects have the method
236 # reindexObjectSecurity, which is in CMFCatalogAware and
237 # thus PortalContent and PortalFolder.
238 obj
.reindexObjectSecurity()
240 def deleteLocalRoles( self
, obj
, member_ids
, reindex
=1 ):
241 """ Delete local roles for members member_ids """
242 member
= self
.getAuthenticatedMember()
243 my_roles
= member
.getRolesInContext( obj
)
244 gruf
= self
.acl_users
246 u
.getUserId() for u
in [
247 gruf
.getUserById(u
) or gruf
.getGroupByName(u
) for u
in member_ids
251 if 'Manager' in my_roles
or 'Owner' in my_roles
:
252 obj
.manage_delLocalRoles( userids
=member_ids
)
255 obj
.reindexObjectSecurity()
258 if PREVIEW_PLONE21_IN_PLONE20_
:
259 from Products
.CMFCore
import MembershipTool
as CMFCoreMembershipTool
260 CMFCoreMembershipTool
.MembershipTool
.setLocalRoles
= setLocalRoles
261 CMFCoreMembershipTool
.MembershipTool
.deleteLocalRoles
= deleteLocalRoles
262 from Products
.CMFPlone
import MemberDataTool
263 from Products
.CMFPlone
import MembershipTool
264 MembershipTool
.MembershipTool
.searchForMembers
= searchForMembers
265 MembershipTool
.MembershipTool
.listAllowedMembers
= listAllowedMembers
266 MemberDataTool
.MemberDataTool
._former
_getPortrait
= MemberDataTool
.MemberDataTool
._getPortrait
267 MemberDataTool
.MemberDataTool
._getPortrait
= _getPortrait
268 Log(LOG_NOTICE
, "Applied GRUF's monkeypatch over Plone 2.0.x. Enjoy!")