1 # -*- coding: utf-8 -*-
2 #######################################################################################
3 # Plinn - http://plinn.org #
4 # Copyright (C) 2005-2007 Benoît PIN <benoit.pin@ensmp.fr> #
6 # This program is free software; you can redistribute it and/or #
7 # modify it under the terms of the GNU General Public License #
8 # as published by the Free Software Foundation; either version 2 #
9 # of the License, or (at your option) any later version. #
11 # This program is distributed in the hope that it will be useful, #
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of #
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
14 # GNU General Public License for more details. #
16 # You should have received a copy of the GNU General Public License #
17 # along with this program; if not, write to the Free Software #
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #
19 #######################################################################################
20 """ Plinn public utilities
27 from random
import randrange
28 from Acquisition
import aq_base
29 from quopri
import encodestring
30 from json
import dumps
as json_dumps
31 from zope
.globalrequest
import getRequest
32 from AccessControl
.PermissionRole
import rolesForPermissionOn
33 from AccessControl
import ModuleSecurityInfo
34 from AccessControl
import getSecurityManager
35 from AccessControl
.User
import UnrestrictedUser
36 from OFS
.CopySupport
import _cb_decode
, _cb_encode
, cookie_path
37 from Products
.CMFCore
.utils
import getToolByName
, getUtilityByInterfaceName
38 from Products
.CMFCore
.exceptions
import BadRequest
39 from Products
.Utf8Splitter
.Utf8Splitter
import Utf8Utils
40 from Globals
import REPLACEABLE
, NOT_REPLACEABLE
, UNIQUE
41 from zope
.i18n
import translate
as i18ntranslate
42 from zope
.i18n
.interfaces
import IUserPreferredLanguages
43 from zope
.i18nmessageid
import MessageFactory
44 from zope
.component
.interfaces
import ComponentLookupError
45 from zope
.dottedname
.resolve
import resolve
as resolve_dotted_name
46 from zope
.component
import queryAdapter
50 security
= ModuleSecurityInfo( 'Products.Plinn.utils' )
52 security
.declarePublic('json_dumps')
54 security
.declarePublic('thisObjectComeFromPortalSkin')
55 def thisObjectComeFromPortalSkin(ob
, portal
=None):
56 """ check if ob comes from portal_skins """
58 portal
= getToolByName(ob
, 'portal_url')
59 portal
= portal
.getPortalObject()
61 if ob
.aq_self
== portal
.aq_self
:
68 sob
= getattr(portal
, obId
, None)
72 elif not(sob
.aq_inner
.aq_self
is ob
.aq_inner
.aq_self
) :
81 security
.declarePublic('listWorkflowActions')
82 def listWorkflowActions(context
) :
83 wftool
= getUtilityByInterfaceName('Products.CMFCore.interfaces.IWorkflowTool')
84 return wftool
.listActions(object=context
)
86 def capitalizeCompoundGivenName(givenName
) :
87 givenName
= givenName
.strip()
88 givenNames
= ' '.join(givenName
.split('-')).split()
89 givenNameCapitalized
= '-'.join(map(string
.capitalize
, givenNames
))
90 return givenNameCapitalized
93 def formatFullName(memberName
, memberGivenName
, memberId
, nameBefore
=1) :
94 memberName
= memberName
.decode('utf-8')
95 memberGivenName
= memberGivenName
.decode('utf-8')
97 if memberName
and memberGivenName
:
99 memberFullName
= memberName
.capitalize() + ' ' + capitalizeCompoundGivenName(memberGivenName
)
101 memberFullName
= capitalizeCompoundGivenName(memberGivenName
) + ' ' + memberName
.capitalize()
103 elif memberName
and not memberGivenName
:
104 memberFullName
= memberName
.capitalize()
106 elif not memberName
and memberGivenName
:
107 memberFullName
= capitalizeCompoundGivenName(memberGivenName
)
110 memberFullName
= memberId
112 return memberFullName
.encode('utf-8')
114 # from OFS.ObjectManager #63
115 bad_url_chars
= re
.compile(r
'[^a-zA-Z0-9-_~,.$\(\)@]')
117 security
.declarePublic('makeValidId')
118 def makeValidId(self
, id, allow_dup
=0):
119 id = Utf8Utils
.desacc(id)
120 id = bad_url_chars
.sub('-', id)
121 # If allow_dup is false, an error will be raised if an object
122 # with the given id already exists. If allow_dup is true,
123 # only check that the id string contains no illegal chars;
124 # check_valid_id() will be called again later with allow_dup
125 # set to false before the object is added.
128 if id in ('.', '..'):
130 if id.startswith('_'):
132 if id.startswith('aq_'):
135 while id.endswith('__') :
138 obj
= getattr(self
, id, None)
140 # An object by the given id exists either in this
141 # ObjectManager or in the acquisition path.
142 flags
= getattr(obj
, '__replaceable__', NOT_REPLACEABLE
)
143 if hasattr(aq_base(self
), id):
144 # The object is located in this ObjectManager.
145 if not flags
& REPLACEABLE
:
147 # else the object is replaceable even if the UNIQUE
154 if makeRandomId
is True :
155 id = str(randrange(2,10000)) + id
160 def _checkMemberPermission(userid
, permission
, obj
, StringType
= type('')):
161 user
= obj
.aq_inner
.acl_users
.getUser(userid
)
162 roles
= rolesForPermissionOn(permission
, obj
)
163 if type(roles
) is StringType
:
165 if user
.allowed( obj
, roles
):
169 def getCPInfo(self
) :
170 if self
.REQUEST
.RESPONSE
.cookies
.has_key('__cp') :
171 cp
= self
.REQUEST
.RESPONSE
.cookies
['__cp']['value']
173 cp
= self
.REQUEST
.get('__cp')
174 try: cp
= _cb_decode(cp
)
179 def popCP(self
, indexes
=None) :
180 try: cp
= _cb_decode(self
.REQUEST
['__cp'])
184 if indexes
is not None :
185 indexes
= list(indexes
)
188 for index
in indexes
:
194 self
.REQUEST
.RESPONSE
.expireCookie('__cp', path
=self
.REQUEST
['BASEPATH1'] or "/")
197 cp
= _cb_encode( (cp
[0], paths
) )
198 resp
= self
.REQUEST
['RESPONSE']
199 resp
.setCookie('__cp', cp
, path
='%s' % cookie_path(self
.REQUEST
))
201 security
.declarePublic('Message')
202 Message
= MessageFactory('plinn')
204 security
.declarePublic('translate')
205 def translate(message
, context
=None):
206 """ Translate i18n message.
208 if isinstance(message
, Exception):
211 except (TypeError, IndexError):
214 request
= getRequest()
216 request
= context
.REQUEST
217 return i18ntranslate(message
, domain
='plinn', context
=request
)
219 security
.declarePublic('desacc')
220 desacc
= Utf8Utils
.desacc
222 security
.declarePublic('getPreferredLanguages')
223 def getPreferredLanguages(context
):
224 """ returns browser prefered languages"""
225 request
= getattr(context
, 'REQUEST', None)
226 if request
is not None :
227 adapter
= IUserPreferredLanguages(request
, None)
228 if adapter
is not None :
229 return adapter
.getPreferredLanguages()
232 security
.declarePublic('getBestTranslationLanguage')
233 def getBestTranslationLanguage(langs
, context
):
234 """ returns best translation language according
235 to available languages (param langs)
236 and user preferences (retrieves by context)
238 request
= getattr(context
, 'REQUEST', None)
240 negociator
= getUtilityByInterfaceName('zope.i18n.interfaces.INegotiator')
241 return negociator
.getLanguage(langs
, request
) or langs
[0]
245 security
.declarePublic('getAdapterByInterface')
246 def getAdapterByInterface(ob
, dotted_name
, default
=_marker
) :
247 """ Get the adapter which provides the interface on the given object.
250 iface
= resolve_dotted_name(dotted_name
)
252 if default
is _marker
:
253 raise ComponentLookupError
, dotted_name
256 adapter
= queryAdapter(ob
, iface
, default
=default
)
257 if adapter
is _marker
:
258 raise ComponentLookupError
, "no adapter providing %r found on %r" % (dotted_name
, ob
)
260 # the adapter must be wrapped to allow security mahinery to work.
261 if adapter
!= default
:
262 return adapter
.__of
__(ob
)
266 security
.declarePublic('encodeQuopriEmail')
267 def encodeQuopriEmail(name
, email
) :
268 qpName
= encodestring(name
).replace('=\n', '')
269 return '''"=?utf-8?q?%s?=" <%s>''' % (qpName
, email
)
271 security
.declarePublic('encodeMailHeader')
272 def encodeMailHeader(content
) :
273 s
= encodestring(content
).replace('=\n', '')
274 s
= s
.replace('_', '=5F')
275 s
= s
.replace(' ', '_')
284 while len(part
) == STEP
:
290 lines
= [' =?utf-8?Q?%s?=' % part
for part
in lines
]
296 def _sudo(func
, userid
=None) :
298 execute func or any callable object
299 without restriction. Used to switch off
300 security assertions (eg. checkPermission) encountered
301 during the execution.
304 sm
= getSecurityManager()
305 restrictedUser
= sm
.getUser()
308 userid
= restrictedUser
.getId()
310 sm
._context
.user
= UnrestrictedUser(userid
, '', (), ())
315 except Exception, e
:
318 sm
._context
.user
= restrictedUser
320 if deferedEx
is not None :
325 security
.declarePublic('searchContentsWithLocalRolesForAuthenticatedUser')
326 def searchContentsWithLocalRolesForAuthenticatedUser(**kw
):
327 mtool
= getUtilityByInterfaceName('Products.CMFCore.interfaces.IMembershipTool')
328 ctool
= getUtilityByInterfaceName('Products.CMFCore.interfaces.ICatalogTool')
329 member
= mtool
.getAuthenticatedMember()
330 userid
= member
.getId()
331 userAndGroups
= ['user:%s' % userid
]
333 getGroups
= getattr(member
, 'getGroups', None)
334 if getGroups
is not None :
335 for group
in getGroups():
336 userAndGroups
.append('user:'+group
)
338 kw
[ 'allowedRolesAndUsers' ] = userAndGroups
340 return ctool
.unrestrictedSearchResults(**kw
)