paula.testing: test for finding txt files + minor bugfix
[paula.git] / paula.pasplugins / src / paula / pasplugins / plugins / properties.py
blob6e7e779df9163c2ad478eed6b44cfe0ed6aa63e8
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/>.
18 """
19 """
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.
52 """
53 plugin = PropertiesPlugin(id, title)
54 dispatcher._setObject(plugin.getId(), plugin)
56 if REQUEST is not None:
57 REQUEST['RESPONSE'].redirect(
58 '%s/manage_workspace'
59 '?manage_tabs_message='
60 'paula.plonepas.PropertiesPlugin+added.'
61 % dispatcher.absolute_url())
63 paula_properties_ifs = (
64 IPropertiesPlugin,
67 class PropertiesPlugin(BasePlugin):
68 """
69 """
70 security = ClassSecurityInfo()
72 implements(
73 IMutablePropertiesPlugin,
74 *paula_properties_ifs
77 meta_type = "Paula PAS Properties Plugin"
79 def __init__(self, id, title=None):
80 self._id = self.id = id
81 self.title = title
83 security.declarePrivate('getPropertiesForUser')
84 def getPropertiesForUser(self, user, request=None):
85 """ user -> {}
87 o User will implement IPropertiedUser.
89 o Plugin should return a dictionary or an object providing
90 IPropertySheet.
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
96 present
98 Create a sophisticated mock principal
100 >>> from zope.interface import Interface, Attribute
102 property interfaces
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)
115 True
116 >>> IPropertyInterface.providedBy(IB)
117 True
119 and the mock principal
121 >>> class MockPrincipal(object):
122 ... implements(IA,IB)
123 ... id = 'login'
124 ... a1 = 1
125 ... a2 = 2
126 ... b1 = 1
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)
138 our property plugin
140 >>> pp = PropertiesPlugin('pp')
142 a mockup plone user
144 >>> ploneuser = Mock(getId = lambda : u"login")
145 >>> psheet = pp.getPropertiesForUser(ploneuser)
146 >>> psheet.getId()
147 'pp'
148 >>> psheet.propertyIds()
149 ['a1', 'a2', 'b1']
150 >>> psheet.propertyValues()
151 [1, 2, 1]
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)
161 try:
162 #XXX: cache at least per request!
163 #XXX: is called already in auth plugin
164 principal = pau.getPrincipal(user.getId())
165 except PrincipalLookupError:
166 return {}
168 if not principal:
169 return {}
171 # create property dictionary from all attributes, which belong to
172 # property schemas
173 properties = {}
174 for schema in list(principal.__provides__):
175 if IPropertyInterface.providedBy(schema):
176 for name in list(schema):
177 try:
178 properties[name] = getattr(principal, name)
179 except AttributeError:
180 # we should write a log message
181 pass
183 if properties.has_key('id'):
184 del properties['id']
186 psheet = MutablePropertySheet(self.id, **properties)
187 return psheet
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)