Back to index

plone3  3.1.7
MemberDataTool.py
Go to the documentation of this file.
00001 ##############################################################################
00002 #
00003 # Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
00004 #
00005 # This software is subject to the provisions of the Zope Public License,
00006 # Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
00007 # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
00008 # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00009 # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
00010 # FOR A PARTICULAR PURPOSE.
00011 #
00012 ##############################################################################
00013 """ Basic member data tool.
00014 
00015 $Id: MemberDataTool.py 77186 2007-06-28 19:06:19Z yuppie $
00016 """
00017 
00018 from AccessControl import ClassSecurityInfo
00019 from Acquisition import aq_inner, aq_parent, aq_base
00020 from BTrees.OOBTree import OOBTree
00021 from Globals import DTMLFile
00022 from Globals import InitializeClass
00023 from OFS.PropertyManager import PropertyManager
00024 from OFS.SimpleItem import SimpleItem
00025 from zope.interface import implements
00026 from ZPublisher.Converters import type_converters
00027 
00028 from exceptions import BadRequest
00029 from interfaces import IMemberData
00030 from interfaces import IMemberDataTool
00031 from interfaces.portal_memberdata import MemberData as z2IMemberData
00032 from interfaces.portal_memberdata \
00033         import portal_memberdata as z2IMemberDataTool
00034 from permissions import ManagePortal
00035 from permissions import SetOwnProperties
00036 from permissions import ViewManagementScreens
00037 from utils import _dtmldir
00038 from utils import getToolByName
00039 from utils import registerToolInterface
00040 from utils import UniqueObject
00041 
00042 _marker = []  # Create a new marker object.
00043 
00044 
00045 class MemberDataTool(UniqueObject, SimpleItem, PropertyManager):
00046 
00047     """ This tool wraps user objects, making them act as Member objects.
00048     """
00049 
00050     implements(IMemberDataTool)
00051     __implements__ = (z2IMemberDataTool, )
00052 
00053     id = 'portal_memberdata'
00054     meta_type = 'CMF Member Data Tool'
00055     _properties = ()
00056 
00057     security = ClassSecurityInfo()
00058 
00059     manage_options=( ({'label': 'Overview',
00060                        'action': 'manage_overview'},
00061                       {'label': 'Contents',
00062                        'action': 'manage_showContents'})
00063                    + PropertyManager.manage_options
00064                    + SimpleItem.manage_options
00065                    )
00066 
00067     #
00068     #   ZMI methods
00069     #
00070     security.declareProtected(ManagePortal, 'manage_overview')
00071     manage_overview = DTMLFile( 'explainMemberDataTool', _dtmldir )
00072 
00073     security.declareProtected(ViewManagementScreens, 'manage_showContents')
00074     manage_showContents = DTMLFile('memberdataContents', _dtmldir )
00075 
00076 
00077     def __init__(self):
00078         self._members = OOBTree()
00079         # Create the default properties.
00080         self._setProperty('email', '', 'string')
00081         self._setProperty('portal_skin', '', 'string')
00082         self._setProperty('listed', '', 'boolean')
00083         self._setProperty('login_time', '2000/01/01', 'date')
00084         self._setProperty('last_login_time', '2000/01/01', 'date')
00085 
00086     #
00087     #   'portal_memberdata' interface methods
00088     #
00089     security.declarePrivate('getMemberDataContents')
00090     def getMemberDataContents(self):
00091         '''
00092         Return the number of members stored in the _members
00093         BTree and some other useful info
00094         '''
00095         # XXX: this method violates the rules for tools/utilities:
00096         # it depends on a non-utility tool
00097         membertool   = getToolByName(self, 'portal_membership')
00098         members      = self._members
00099         user_list    = membertool.listMemberIds()
00100         member_list  = members.keys()
00101         member_count = len(members)
00102         orphan_count = 0
00103 
00104         for member in member_list:
00105             if member not in user_list:
00106                 orphan_count = orphan_count + 1
00107 
00108         return [{ 'member_count' : member_count,
00109                   'orphan_count' : orphan_count }]
00110 
00111     security.declarePrivate('searchMemberData')
00112     def searchMemberData(self, search_param, search_term, attributes=()):
00113         """ Search members. """
00114         # XXX: this method violates the rules for tools/utilities:
00115         # it depends on a non-utility tool
00116         res = []
00117 
00118         if not search_param:
00119             return res
00120 
00121         membership = getToolByName(self, 'portal_membership')
00122 
00123         if len(attributes) == 0:
00124             attributes = ('id', 'email')
00125 
00126         if search_param == 'username':
00127             search_param = 'id'
00128 
00129         for user_id in self._members.keys():
00130             u = membership.getMemberById(user_id)
00131 
00132             if u is not None:
00133                 memberProperty = u.getProperty
00134                 searched = memberProperty(search_param, None)
00135 
00136                 if searched is not None and searched.find(search_term) != -1:
00137                     user_data = {}
00138 
00139                     for desired in attributes:
00140                         if desired == 'id':
00141                             user_data['username'] = memberProperty(desired, '')
00142                         else:
00143                             user_data[desired] = memberProperty(desired, '')
00144 
00145                     res.append(user_data)
00146 
00147         return res
00148 
00149     security.declarePrivate( 'searchMemberDataContents' )
00150     def searchMemberDataContents( self, search_param, search_term ):
00151         """ Search members. This method will be deprecated soon. """
00152         # XXX: this method violates the rules for tools/utilities:
00153         # it depends on a non-utility tool
00154         res = []
00155 
00156         if search_param == 'username':
00157             search_param = 'id'
00158 
00159         mtool   = getToolByName(self, 'portal_membership')
00160 
00161         for member_id in self._members.keys():
00162 
00163             user_wrapper = mtool.getMemberById( member_id )
00164 
00165             if user_wrapper is not None:
00166                 memberProperty = user_wrapper.getProperty
00167                 searched = memberProperty( search_param, None )
00168 
00169                 if searched is not None and searched.find(search_term) != -1:
00170 
00171                     res.append( { 'username': memberProperty( 'id' )
00172                                 , 'email' : memberProperty( 'email', '' )
00173                                 }
00174                             )
00175         return res
00176 
00177     security.declarePrivate('pruneMemberDataContents')
00178     def pruneMemberDataContents(self):
00179         """ Delete data contents of all members not listet in acl_users.
00180         """
00181         # XXX: this method violates the rules for tools/utilities:
00182         # it depends on a non-utility tool
00183         membertool = getToolByName(self, 'portal_membership')
00184         members = self._members
00185         user_list = membertool.listMemberIds()
00186 
00187         for member_id in list(members.keys()):
00188             if member_id not in user_list:
00189                 del members[member_id]
00190 
00191     security.declarePrivate('wrapUser')
00192     def wrapUser(self, u):
00193         '''
00194         If possible, returns the Member object that corresponds
00195         to the given User object.
00196         '''
00197         id = u.getId()
00198         members = self._members
00199         if not id in members:
00200             base = aq_base(self)
00201             members[id] = MemberData(base, id)
00202         # Return a wrapper with self as containment and
00203         # the user as context.
00204         return members[id].__of__(self).__of__(u)
00205 
00206     security.declarePrivate('registerMemberData')
00207     def registerMemberData(self, m, id):
00208         """ Add the given member data to the _members btree.
00209         """
00210         self._members[id] = aq_base(m)
00211 
00212     security.declarePrivate('deleteMemberData')
00213     def deleteMemberData(self, member_id):
00214         """ Delete member data of specified member.
00215         """
00216         members = self._members
00217         if members.has_key(member_id):
00218             del members[member_id]
00219             return 1
00220         else:
00221             return 0
00222 
00223 InitializeClass(MemberDataTool)
00224 registerToolInterface('portal_memberdata', IMemberDataTool)
00225 
00226 
00227 class CleanupTemp:
00228 
00229     """Used to cleanup _v_temps at the end of the request."""
00230 
00231     def __init__(self, tool):
00232         self._tool = tool
00233 
00234     def __del__(self):
00235         try:
00236             del self._tool._v_temps
00237         except (AttributeError, KeyError):
00238             # The object has already been deactivated.
00239             pass
00240 
00241 
00242 class MemberData(SimpleItem):
00243 
00244     implements(IMemberData)
00245     __implements__ = z2IMemberData
00246 
00247     security = ClassSecurityInfo()
00248 
00249     def __init__(self, tool, id):
00250         self.id = id
00251 
00252     security.declarePrivate('notifyModified')
00253     def notifyModified(self):
00254         # Links self to parent for full persistence.
00255         self.getTool().registerMemberData(self, self.getId())
00256 
00257     security.declarePublic('getUser')
00258     def getUser(self):
00259         # The user object is our context, but it's possible for
00260         # restricted code to strip context while retaining
00261         # containment.  Therefore we need a simple security check.
00262         parent = aq_parent(self)
00263         bcontext = aq_base(parent)
00264         bcontainer = aq_base(aq_parent(aq_inner(self)))
00265         if bcontext is bcontainer or not hasattr(bcontext, 'getUserName'):
00266             raise 'MemberDataError', "Can't find user data"
00267         # Return the user object, which is our context.
00268         return parent
00269 
00270     def getTool(self):
00271         return aq_parent(aq_inner(self))
00272 
00273     security.declarePublic('getMemberId')
00274     def getMemberId(self):
00275         return self.getUser().getId()
00276 
00277     security.declareProtected(SetOwnProperties, 'setProperties')
00278     def setProperties(self, properties=None, **kw):
00279         '''Allows the authenticated member to set his/her own properties.
00280         Accepts either keyword arguments or a mapping for the "properties"
00281         argument.
00282         '''
00283         # XXX: this method violates the rules for tools/utilities:
00284         # it depends on a non-utility tool
00285         if properties is None:
00286             properties = kw
00287         membership = getToolByName(self, 'portal_membership')
00288         registration = getToolByName(self, 'portal_registration', None)
00289         if not membership.isAnonymousUser():
00290             member = membership.getAuthenticatedMember()
00291             if registration:
00292                 failMessage = registration.testPropertiesValidity(properties, member)
00293                 if failMessage is not None:
00294                     raise BadRequest(failMessage)
00295             member.setMemberProperties(properties)
00296         else:
00297             raise BadRequest('Not logged in.')
00298 
00299     security.declarePrivate('setMemberProperties')
00300     def setMemberProperties(self, mapping):
00301         '''Sets the properties of the member.
00302         '''
00303         # Sets the properties given in the MemberDataTool.
00304         tool = self.getTool()
00305         for id in tool.propertyIds():
00306             if mapping.has_key(id):
00307                 if not self.__class__.__dict__.has_key(id):
00308                     value = mapping[id]
00309                     if type(value)==type(''):
00310                         proptype = tool.getPropertyType(id) or 'string'
00311                         if type_converters.has_key(proptype):
00312                             value = type_converters[proptype](value)
00313                     setattr(self, id, value)
00314         # Hopefully we can later make notifyModified() implicit.
00315         self.notifyModified()
00316 
00317     # XXX: s.b., getPropertyForMember(member, id, default)?
00318 
00319     security.declarePublic('getProperty')
00320     def getProperty(self, id, default=_marker):
00321 
00322         tool = self.getTool()
00323         base = aq_base( self )
00324 
00325         # First, check the wrapper (w/o acquisition).
00326         value = getattr( base, id, _marker )
00327         if value is not _marker:
00328             return value
00329 
00330         # Then, check the tool and the user object for a value.
00331         tool_value = tool.getProperty( id, _marker )
00332         user_value = getattr( self.getUser(), id, _marker )
00333 
00334         # If the tool doesn't have the property, use user_value or default
00335         if tool_value is _marker:
00336             if user_value is not _marker:
00337                 return user_value
00338             elif default is not _marker:
00339                 return default
00340             else:
00341                 raise ValueError, 'The property %s does not exist' % id
00342 
00343         # If the tool has an empty property and we have a user_value, use it
00344         if not tool_value and user_value is not _marker:
00345             return user_value
00346 
00347         # Otherwise return the tool value
00348         return tool_value
00349 
00350     security.declarePrivate('getPassword')
00351     def getPassword(self):
00352         """Return the password of the user."""
00353         return self.getUser()._getPassword()
00354 
00355     security.declarePrivate('setSecurityProfile')
00356     def setSecurityProfile(self, password=None, roles=None, domains=None):
00357         """Set the user's basic security profile"""
00358         u = self.getUser()
00359 
00360         # The Zope User API is stupid, it should check for None.
00361         if roles is None:
00362             roles = list(u.getRoles())
00363             if 'Authenticated' in roles:
00364                 roles.remove('Authenticated')
00365         if domains is None:
00366             domains = u.getDomains()
00367 
00368         u.userFolderEditUser(u.getUserName(), password, roles, domains)
00369 
00370     def __str__(self):
00371         return self.getMemberId()
00372 
00373     ### User object interface ###
00374 
00375     security.declarePublic('getUserName')
00376     def getUserName(self):
00377         """Return the username of a user"""
00378         return self.getUser().getUserName()
00379 
00380     security.declarePublic('getId')
00381     def getId(self):
00382         """Get the ID of the user. The ID can be used, at least from
00383         Python, to get the user from the user's
00384         UserDatabase"""
00385         return self.getUser().getId()
00386 
00387     security.declarePublic('getRoles')
00388     def getRoles(self):
00389         """Return the list of roles assigned to a user."""
00390         return self.getUser().getRoles()
00391 
00392     security.declarePublic('getRolesInContext')
00393     def getRolesInContext(self, object):
00394         """Return the list of roles assigned to the user,
00395            including local roles assigned in context of
00396            the passed in object."""
00397         return self.getUser().getRolesInContext(object)
00398 
00399     security.declarePublic('getDomains')
00400     def getDomains(self):
00401         """Return the list of domain restrictions for a user"""
00402         return self.getUser().getDomains()
00403 
00404     security.declarePublic('has_role')
00405     def has_role(self, roles, object=None):
00406         """Check to see if a user has a given role or roles."""
00407         return self.getUser().has_role(roles, object)
00408 
00409     # There are other parts of the interface but they are
00410     # deprecated for use with CMF applications.
00411 
00412 InitializeClass(MemberData)