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 types
import StringType
28 from random
import randrange
29 from Acquisition
import aq_base
30 from quopri
import encodestring
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('thisObjectComeFromPortalSkin')
53 def thisObjectComeFromPortalSkin(ob
, portal
=None):
54 """ check if ob comes from portal_skins """
56 portal
= getToolByName(ob
, 'portal_url')
57 portal
= portal
.getPortalObject()
59 if ob
.aq_self
== portal
.aq_self
:
66 sob
= getattr(portal
, obId
, None)
70 elif not(sob
.aq_inner
.aq_self
is ob
.aq_inner
.aq_self
) :
79 security
.declarePublic('listActionProviders_')
80 def listActionProviders_(context
) :
81 atool
= getToolByName(context
, 'portal_actions')
82 return atool
.listActionProviders()
84 def capitalizeCompoundGivenName(givenName
) :
85 givenName
= givenName
.strip()
86 givenNames
= ' '.join(givenName
.split('-')).split()
87 givenNameCapitalized
= '-'.join(map(string
.capitalize
, givenNames
))
88 return givenNameCapitalized
91 def formatFullName(memberName
, memberGivenName
, memberId
, nameBefore
=1) :
92 memberName
= memberName
.decode('utf-8')
93 memberGivenName
= memberGivenName
.decode('utf-8')
95 if memberName
and memberGivenName
:
97 memberFullName
= memberName
.upper() + ' ' + capitalizeCompoundGivenName(memberGivenName
)
99 memberFullName
= capitalizeCompoundGivenName(memberGivenName
) + ' ' + memberName
.upper()
101 elif memberName
and not memberGivenName
:
102 memberFullName
= memberName
.upper()
104 elif not memberName
and memberGivenName
:
105 memberFullName
= capitalizeCompoundGivenName(memberGivenName
)
108 memberFullName
= memberId
110 return memberFullName
.encode('utf-8')
112 # from OFS.ObjectManager #63
113 bad_url_chars
= re
.compile(r
'[^a-zA-Z0-9-_~,.$\(\)@]')
115 security
.declarePublic('makeValidId')
116 def makeValidId(self
, id, allow_dup
=0):
117 id = Utf8Utils
.desacc(id)
118 id = bad_url_chars
.sub('-', id)
119 # If allow_dup is false, an error will be raised if an object
120 # with the given id already exists. If allow_dup is true,
121 # only check that the id string contains no illegal chars;
122 # check_valid_id() will be called again later with allow_dup
123 # set to false before the object is added.
126 if id in ('.', '..'):
128 if id.startswith('_'):
130 if id.startswith('aq_'):
133 while id.endswith('__') :
136 obj
= getattr(self
, id, None)
138 # An object by the given id exists either in this
139 # ObjectManager or in the acquisition path.
140 flags
= getattr(obj
, '__replaceable__', NOT_REPLACEABLE
)
141 if hasattr(aq_base(self
), id):
142 # The object is located in this ObjectManager.
143 if not flags
& REPLACEABLE
:
145 # else the object is replaceable even if the UNIQUE
152 if makeRandomId
is True :
153 id = str(randrange(2,10000)) + id
158 def _checkMemberPermission(userid
, permission
, obj
, StringType
= type('')):
159 user
= obj
.aq_inner
.acl_users
.getUser(userid
)
160 roles
= rolesForPermissionOn(permission
, obj
)
161 if type(roles
) is StringType
:
163 if user
.allowed( obj
, roles
):
167 def getCPInfo(self
) :
168 try: cp
= _cb_decode(self
.REQUEST
['__cp'])
173 def popCP(self
, indexes
=None) :
174 try: cp
= _cb_decode(self
.REQUEST
['__cp'])
178 if indexes
is not None :
179 indexes
= list(indexes
)
182 for index
in indexes
:
188 self
.REQUEST
.RESPONSE
.expireCookie('__cp', path
=self
.REQUEST
['BASEPATH1'] or "/")
191 cp
= _cb_encode( (cp
[0], paths
) )
192 resp
= self
.REQUEST
['RESPONSE']
193 resp
.setCookie('__cp', cp
, path
='%s' % cookie_path(self
.REQUEST
))
195 security
.declarePublic('Message')
196 Message
= MessageFactory('plinn')
198 security
.declarePublic('translate')
199 def translate(message
, context
=None):
200 """ Translate i18n message.
202 if isinstance(message
, Exception):
205 except (TypeError, IndexError):
208 request
= getRequest()
210 request
= context
.REQUEST
211 return i18ntranslate(message
, domain
='plinn', context
=request
)
213 security
.declarePublic('desacc')
214 desacc
= Utf8Utils
.desacc
216 security
.declarePublic('getPreferredLanguages')
217 def getPreferredLanguages(context
):
218 """ returns browser prefered languages"""
219 request
= getattr(context
, 'REQUEST', None)
220 if request
is not None :
221 adapter
= IUserPreferredLanguages(request
, None)
222 if adapter
is not None :
223 return adapter
.getPreferredLanguages()
226 security
.declarePublic('getBestTranslationLanguage')
227 def getBestTranslationLanguage(langs
, context
):
228 """ returns best translation language according
229 availables languages (param langs)
230 and user preferences (retrieves by context)
232 request
= getattr(context
, 'REQUEST', None)
234 negociator
= getUtilityByInterfaceName('zope.i18n.interfaces.INegotiator')
235 return negociator
.getLanguage(langs
, request
) or langs
[0]
239 security
.declarePublic('getAdapterByInterface')
240 def getAdapterByInterface(ob
, dotted_name
, default
=_marker
) :
241 """ Get the adapter which provides the interface on the given object.
244 iface
= resolve_dotted_name(dotted_name
)
246 if default
is _marker
:
247 raise ComponentLookupError
, dotted_name
250 adapter
= queryAdapter(ob
, iface
, default
=default
)
251 if adapter
is _marker
:
252 raise ComponentLookupError
, "no adapter providing %r found on %r" % (dotted_name
, ob
)
254 # the adapter must be wrapped to allow security mahinery to work.
255 if adapter
!= default
:
256 return adapter
.__of
__(ob
)
260 def encodeQuopriEmail(name
, email
) :
261 qpName
= encodestring(name
).replace('=\n', '')
262 return '''"=?utf-8?q?%s?=" <%s>''' % (qpName
, email
)
265 def _sudo(func
, userid
=None) :
267 execute func or any callable object
268 without restriction. Used to switch off
269 security assertions (eg. checkPermission) encountered
270 during the execution.
273 sm
= getSecurityManager()
274 restrictedUser
= sm
.getUser()
277 userid
= restrictedUser
.getId()
279 sm
._context
.user
= UnrestrictedUser(userid
, '', (), ())
284 except Exception, e
:
287 sm
._context
.user
= restrictedUser
289 if deferedEx
is not None :