vendor/CMF/1.6.3/CMFCore

view MemberDataTool.py @ 2:4c712d7bd1d7

Added tag 1.6.3 for changeset 1babb9d61518
author Georges Racinet on purity.racinet.fr <georges@racinet.fr>
date Fri, 09 Sep 2011 12:44:00 +0200
parents
children
line source
1 ##############################################################################
2 #
3 # Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
4 #
5 # This software is subject to the provisions of the Zope Public License,
6 # Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
7 # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
8 # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
9 # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
10 # FOR A PARTICULAR PURPOSE.
11 #
12 ##############################################################################
13 """ Basic member data tool.
15 $Id$
16 """
18 from AccessControl import ClassSecurityInfo
19 from Acquisition import aq_inner, aq_parent, aq_base
20 from BTrees.OOBTree import OOBTree
21 from Globals import DTMLFile
22 from Globals import InitializeClass
23 from OFS.PropertyManager import PropertyManager
24 from OFS.SimpleItem import SimpleItem
25 from ZPublisher.Converters import type_converters
27 from ActionProviderBase import ActionProviderBase
28 from exceptions import BadRequest
29 from interfaces.portal_memberdata import MemberData as IMemberData
30 from interfaces.portal_memberdata import portal_memberdata as IMemberDataTool
31 from permissions import ManagePortal
32 from permissions import SetOwnProperties
33 from permissions import ViewManagementScreens
34 from utils import _dtmldir
35 from utils import getToolByName
36 from utils import UniqueObject
39 _marker = [] # Create a new marker object.
42 class MemberDataTool (UniqueObject, SimpleItem, PropertyManager, ActionProviderBase):
43 """ This tool wraps user objects, making them act as Member objects.
44 """
46 __implements__ = (IMemberDataTool, ActionProviderBase.__implements__)
48 id = 'portal_memberdata'
49 meta_type = 'CMF Member Data Tool'
50 _actions = ()
52 _v_temps = None
53 _properties = ()
55 security = ClassSecurityInfo()
57 manage_options=( ActionProviderBase.manage_options +
58 ({ 'label' : 'Overview'
59 , 'action' : 'manage_overview'
60 }
61 , { 'label' : 'Contents'
62 , 'action' : 'manage_showContents'
63 }
64 )
65 + PropertyManager.manage_options
66 + SimpleItem.manage_options
67 )
69 #
70 # ZMI methods
71 #
72 security.declareProtected(ManagePortal, 'manage_overview')
73 manage_overview = DTMLFile( 'explainMemberDataTool', _dtmldir )
75 security.declareProtected(ViewManagementScreens, 'manage_showContents')
76 manage_showContents = DTMLFile('memberdataContents', _dtmldir )
79 def __init__(self):
80 self._members = OOBTree()
81 # Create the default properties.
82 self._setProperty('email', '', 'string')
83 self._setProperty('portal_skin', '', 'string')
84 self._setProperty('listed', '', 'boolean')
85 self._setProperty('login_time', '2000/01/01', 'date')
86 self._setProperty('last_login_time', '2000/01/01', 'date')
88 #
89 # 'portal_memberdata' interface methods
90 #
91 security.declarePrivate('getMemberDataContents')
92 def getMemberDataContents(self):
93 '''
94 Return the number of members stored in the _members
95 BTree and some other useful info
96 '''
97 membertool = getToolByName(self, 'portal_membership')
98 members = self._members
99 user_list = membertool.listMemberIds()
100 member_list = members.keys()
101 member_count = len(members)
102 orphan_count = 0
104 for member in member_list:
105 if member not in user_list:
106 orphan_count = orphan_count + 1
108 return [{ 'member_count' : member_count,
109 'orphan_count' : orphan_count }]
111 security.declarePrivate('searchMemberData')
112 def searchMemberData(self, search_param, search_term, attributes=()):
113 """ Search members. """
114 res = []
116 if not search_param:
117 return res
119 membership = getToolByName(self, 'portal_membership')
121 if len(attributes) == 0:
122 attributes = ('id', 'email')
124 if search_param == 'username':
125 search_param = 'id'
127 for user_id in self._members.keys():
128 u = membership.getMemberById(user_id)
130 if u is not None:
131 memberProperty = u.getProperty
132 searched = memberProperty(search_param, None)
134 if searched is not None and searched.find(search_term) != -1:
135 user_data = {}
137 for desired in attributes:
138 if desired == 'id':
139 user_data['username'] = memberProperty(desired, '')
140 else:
141 user_data[desired] = memberProperty(desired, '')
143 res.append(user_data)
145 return res
147 security.declarePrivate( 'searchMemberDataContents' )
148 def searchMemberDataContents( self, search_param, search_term ):
149 """ Search members. This method will be deprecated soon. """
150 res = []
152 if search_param == 'username':
153 search_param = 'id'
155 mtool = getToolByName(self, 'portal_membership')
157 for member_id in self._members.keys():
159 user_wrapper = mtool.getMemberById( member_id )
161 if user_wrapper is not None:
162 memberProperty = user_wrapper.getProperty
163 searched = memberProperty( search_param, None )
165 if searched is not None and searched.find(search_term) != -1:
167 res.append( { 'username': memberProperty( 'id' )
168 , 'email' : memberProperty( 'email', '' )
169 }
170 )
171 return res
173 security.declarePrivate('pruneMemberDataContents')
174 def pruneMemberDataContents(self):
175 """ Delete data contents of all members not listet in acl_users.
176 """
177 membertool= getToolByName(self, 'portal_membership')
178 members = self._members
179 user_list = membertool.listMemberIds()
181 for member_id in list(members.keys()):
182 if member_id not in user_list:
183 del members[member_id]
185 security.declarePrivate('wrapUser')
186 def wrapUser(self, u):
187 '''
188 If possible, returns the Member object that corresponds
189 to the given User object.
190 '''
191 id = u.getId()
192 members = self._members
193 if not members.has_key(id):
194 # Get a temporary member that might be
195 # registered later via registerMemberData().
196 temps = self._v_temps
197 if temps is not None and temps.has_key(id):
198 m = temps[id]
199 else:
200 base = aq_base(self)
201 m = MemberData(base, id)
202 if temps is None:
203 self._v_temps = {id:m}
204 if hasattr(self, 'REQUEST'):
205 # No REQUEST during tests.
206 self.REQUEST._hold(CleanupTemp(self))
207 else:
208 temps[id] = m
209 else:
210 m = members[id]
211 # Return a wrapper with self as containment and
212 # the user as context.
213 return m.__of__(self).__of__(u)
215 security.declarePrivate('registerMemberData')
216 def registerMemberData(self, m, id):
217 """ Add the given member data to the _members btree.
218 """
219 self._members[id] = aq_base(m)
221 security.declarePrivate('deleteMemberData')
222 def deleteMemberData(self, member_id):
223 """ Delete member data of specified member.
224 """
225 members = self._members
226 if members.has_key(member_id):
227 del members[member_id]
228 return 1
229 else:
230 return 0
232 InitializeClass(MemberDataTool)
235 class CleanupTemp:
236 """Used to cleanup _v_temps at the end of the request."""
237 def __init__(self, tool):
238 self._tool = tool
239 def __del__(self):
240 try:
241 del self._tool._v_temps
242 except (AttributeError, KeyError):
243 # The object has already been deactivated.
244 pass
247 class MemberData (SimpleItem):
249 __implements__ = IMemberData
251 security = ClassSecurityInfo()
253 def __init__(self, tool, id):
254 self.id = id
255 # Make a temporary reference to the tool.
256 # The reference will be removed by notifyModified().
257 self._tool = tool
259 security.declarePrivate('notifyModified')
260 def notifyModified(self):
261 # Links self to parent for full persistence.
262 tool = getattr(self, '_tool', None)
263 if tool is not None:
264 del self._tool
265 tool.registerMemberData(self, self.getId())
267 security.declarePublic('getUser')
268 def getUser(self):
269 # The user object is our context, but it's possible for
270 # restricted code to strip context while retaining
271 # containment. Therefore we need a simple security check.
272 parent = aq_parent(self)
273 bcontext = aq_base(parent)
274 bcontainer = aq_base(aq_parent(aq_inner(self)))
275 if bcontext is bcontainer or not hasattr(bcontext, 'getUserName'):
276 raise 'MemberDataError', "Can't find user data"
277 # Return the user object, which is our context.
278 return parent
280 def getTool(self):
281 return aq_parent(aq_inner(self))
283 security.declarePublic('getMemberId')
284 def getMemberId(self):
285 return self.getUser().getId()
287 security.declareProtected(SetOwnProperties, 'setProperties')
288 def setProperties(self, properties=None, **kw):
289 '''Allows the authenticated member to set his/her own properties.
290 Accepts either keyword arguments or a mapping for the "properties"
291 argument.
292 '''
293 if properties is None:
294 properties = kw
295 membership = getToolByName(self, 'portal_membership')
296 registration = getToolByName(self, 'portal_registration', None)
297 if not membership.isAnonymousUser():
298 member = membership.getAuthenticatedMember()
299 if registration:
300 failMessage = registration.testPropertiesValidity(properties, member)
301 if failMessage is not None:
302 raise BadRequest(failMessage)
303 member.setMemberProperties(properties)
304 else:
305 raise BadRequest('Not logged in.')
307 security.declarePrivate('setMemberProperties')
308 def setMemberProperties(self, mapping):
309 '''Sets the properties of the member.
310 '''
311 # Sets the properties given in the MemberDataTool.
312 tool = self.getTool()
313 for id in tool.propertyIds():
314 if mapping.has_key(id):
315 if not self.__class__.__dict__.has_key(id):
316 value = mapping[id]
317 if type(value)==type(''):
318 proptype = tool.getPropertyType(id) or 'string'
319 if type_converters.has_key(proptype):
320 value = type_converters[proptype](value)
321 setattr(self, id, value)
322 # Hopefully we can later make notifyModified() implicit.
323 self.notifyModified()
325 # XXX: s.b., getPropertyForMember(member, id, default)?
327 security.declarePublic('getProperty')
328 def getProperty(self, id, default=_marker):
330 tool = self.getTool()
331 base = aq_base( self )
333 # First, check the wrapper (w/o acquisition).
334 value = getattr( base, id, _marker )
335 if value is not _marker:
336 return value
338 # Then, check the tool and the user object for a value.
339 tool_value = tool.getProperty( id, _marker )
340 user_value = getattr( self.getUser(), id, _marker )
342 # If the tool doesn't have the property, use user_value or default
343 if tool_value is _marker:
344 if user_value is not _marker:
345 return user_value
346 elif default is not _marker:
347 return default
348 else:
349 raise ValueError, 'The property %s does not exist' % id
351 # If the tool has an empty property and we have a user_value, use it
352 if not tool_value and user_value is not _marker:
353 return user_value
355 # Otherwise return the tool value
356 return tool_value
358 security.declarePrivate('getPassword')
359 def getPassword(self):
360 """Return the password of the user."""
361 return self.getUser()._getPassword()
363 security.declarePrivate('setSecurityProfile')
364 def setSecurityProfile(self, password=None, roles=None, domains=None):
365 """Set the user's basic security profile"""
366 u = self.getUser()
368 # The Zope User API is stupid, it should check for None.
369 if roles is None:
370 roles = list(u.getRoles())
371 if 'Authenticated' in roles:
372 roles.remove('Authenticated')
373 if domains is None:
374 domains = u.getDomains()
376 u.userFolderEditUser(u.getUserName(), password, roles, domains)
378 def __str__(self):
379 return self.getMemberId()
381 ### User object interface ###
383 security.declarePublic('getUserName')
384 def getUserName(self):
385 """Return the username of a user"""
386 return self.getUser().getUserName()
388 security.declarePublic('getId')
389 def getId(self):
390 """Get the ID of the user. The ID can be used, at least from
391 Python, to get the user from the user's
392 UserDatabase"""
393 return self.getUser().getId()
395 security.declarePublic('getRoles')
396 def getRoles(self):
397 """Return the list of roles assigned to a user."""
398 return self.getUser().getRoles()
400 security.declarePublic('getRolesInContext')
401 def getRolesInContext(self, object):
402 """Return the list of roles assigned to the user,
403 including local roles assigned in context of
404 the passed in object."""
405 return self.getUser().getRolesInContext(object)
407 security.declarePublic('getDomains')
408 def getDomains(self):
409 """Return the list of domain restrictions for a user"""
410 return self.getUser().getDomains()
412 security.declarePublic('has_role')
413 def has_role(self, roles, object=None):
414 """Check to see if a user has a given role or roles."""
415 return self.getUser().has_role(roles, object)
417 # There are other parts of the interface but they are
418 # deprecated for use with CMF applications.
420 InitializeClass(MemberData)