1 # Copyright (c) 2008 by Florian Friesdorf
3 # GNU Affero General Public License (AGPL)
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License as
7 # published by the Free Software Foundation; either version 3 of the
8 # License, or (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 Affero General Public License for more details.
15 # You should have received a copy of the GNU Affero General Public
16 # License along with this program. If not, see
17 # <http://www.gnu.org/licenses/>.
20 __author__
= "Florian Friesdorf <flo@chaoflow.net>"
21 __docformat__
= "plaintext"
24 from AccessControl
import ClassSecurityInfo
25 from Globals
import InitializeClass
27 from Products
.PageTemplates
.PageTemplateFile
import PageTemplateFile
29 from Products
.PlonePAS
.sheet
import MutablePropertySheet
30 from Products
.PlonePAS
.interfaces
.plugins
import IMutablePropertiesPlugin
32 from Products
.PluggableAuthService
.plugins
.BasePlugin
import BasePlugin
33 from Products
.PluggableAuthService
.interfaces
.plugins \
34 import IPropertiesPlugin
36 from zope
.app
.security
.interfaces
import IAuthentication
37 from zope
.app
.security
.interfaces
import PrincipalLookupError
39 from zope
.component
import getUtility
40 from zope
.interface
import alsoProvides
, implements
42 from paula
.pau_addons
.interfaces
import IPropertyInterface
45 manage_addPropertiesPluginForm
= PageTemplateFile(
46 '../www/PropertiesPluginForm',
47 globals(), __name__
='manage_addPropertiesPluginForm' )
50 def addPropertiesPlugin( dispatcher
, id, title
=None, REQUEST
=None ):
51 """Add a paula.plonepas PropertiesPlugin to a PluggableAuthService.
53 plugin
= PropertiesPlugin(id, title
)
54 dispatcher
._setObject
(plugin
.getId(), plugin
)
56 if REQUEST
is not None:
57 REQUEST
['RESPONSE'].redirect(
59 '?manage_tabs_message='
60 'paula.plonepas.PropertiesPlugin+added.'
61 % dispatcher
.absolute_url())
63 paula_properties_ifs
= (
67 class PropertiesPlugin(BasePlugin
):
70 security
= ClassSecurityInfo()
73 IMutablePropertiesPlugin
,
77 meta_type
= "Paula PAS Properties Plugin"
79 def __init__(self
, id, title
=None):
80 self
._id
= self
.id = id
83 security
.declarePrivate('getPropertiesForUser')
84 def getPropertiesForUser(self
, user
, request
=None):
87 o User will implement IPropertiedUser.
89 o Plugin should return a dictionary or an object providing
92 o Plugin may scribble on the user, if needed (but must still
93 return a mapping, even if empty).
95 o May assign properties based on values in the REQUEST object, if
98 Create a sophisticated mock principal
100 >>> from zope.interface import Interface, Attribute
104 >>> class IA(Interface):
105 ... id = Attribute('id')
106 ... a1 = Attribute("a1")
107 ... a2 = Attribute("a2")
109 >>> class IB(Interface):
110 ... b1 = Attribute("b1")
112 >>> alsoProvides(IA, IPropertyInterface)
113 >>> alsoProvides(IB, IPropertyInterface)
114 >>> IPropertyInterface.providedBy(IA)
116 >>> IPropertyInterface.providedBy(IB)
119 and the mock principal
121 >>> class MockPrincipal(object):
122 ... implements(IA,IB)
127 ... c1 = 'will not show up'
129 >>> p = MockPrincipal()
131 Mockup IPluggableAuthentication
133 >>> from zope.component import provideUtility
134 >>> au = Mock(getPrincipal = lambda x : x == "login" and p)
135 >>> alsoProvides(au, IAuthentication)
136 >>> provideUtility(au, IAuthentication)
140 >>> pp = PropertiesPlugin('pp')
144 >>> ploneuser = Mock(getId = lambda : u"login")
145 >>> psheet = pp.getPropertiesForUser(ploneuser)
148 >>> psheet.propertyIds()
150 >>> psheet.propertyValues()
153 and for a non-existing user
155 >>> ploneuser = Mock(getId = lambda : u"foo")
156 >>> pp.getPropertiesForUser(ploneuser)
159 # get principal from pau
160 pau
= getUtility(IAuthentication
)
162 #XXX: cache at least per request!
163 #XXX: is called already in auth plugin
164 principal
= pau
.getPrincipal(user
.getId())
165 except PrincipalLookupError
:
171 # create property dictionary from all attributes, which belong to
174 for schema
in list(principal
.__provides
__):
175 if IPropertyInterface
.providedBy(schema
):
176 for name
in list(schema
):
178 properties
[name
] = getattr(principal
, name
)
179 except AttributeError:
180 # we should write a log message
183 if properties
.has_key('id'):
186 psheet
= MutablePropertySheet(self
.id, **properties
)
189 def setPropertiesForUser(self
, user
, psheet
):
191 Set modified properties on the user persistently.
193 Raise a ValueError if the property or property value is invalid
195 #XXX: This is a hack - properties should not be handled by auth
196 pau
= getUtility(IAuthentication
)
197 props
= dict(psheet
.propertyItems())
198 return pau
.setPropertiesForUser(user
, **props
)
200 InitializeClass( PropertiesPlugin
)