Bugfix sur la boîte des actualités : affichage de la date de modification (au lieu...
[Plinn.git] / utils.py
1 # -*- coding: utf-8 -*-
2 #######################################################################################
3 # Plinn - http://plinn.org #
4 # Copyright (C) 2005-2007 Benoît PIN <benoit.pin@ensmp.fr> #
5 # #
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. #
10 # #
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. #
15 # #
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
21
22
23 """
24
25 import string
26 import re
27 from types import StringType
28 from random import randrange
29 from Acquisition import aq_base
30 from AccessControl.PermissionRole import rolesForPermissionOn
31 from AccessControl import ModuleSecurityInfo
32 from AccessControl import getSecurityManager
33 from AccessControl.User import UnrestrictedUser
34 from OFS.CopySupport import _cb_decode, _cb_encode, cookie_path
35 from Products.CMFCore.utils import getToolByName, getUtilityByInterfaceName
36 from Products.CMFCore.exceptions import BadRequest
37 from Products.Utf8Splitter.Utf8Splitter import Utf8Utils
38 from Globals import REPLACEABLE, NOT_REPLACEABLE, UNIQUE
39 from zope.i18n import translate as i18ntranslate
40 from zope.i18n.interfaces import IUserPreferredLanguages
41 from zope.i18nmessageid import MessageFactory
42 from zope.component.interfaces import ComponentLookupError
43 from zope.dottedname.resolve import resolve as resolve_dotted_name
44 from zope.component import queryAdapter
45
46 _marker = []
47
48 security = ModuleSecurityInfo( 'Products.Plinn.utils' )
49
50 security.declarePublic('thisObjectComeFromPortalSkin')
51 def thisObjectComeFromPortalSkin(ob, portal=None):
52 """ check if ob comes from portal_skins """
53 if not portal :
54 portal = getToolByName(ob, 'portal_url')
55 portal = portal.getPortalObject()
56
57 if ob.aq_self == portal.aq_self :
58 return False
59
60 obId = ob.id
61 if callable(obId) :
62 obId = obId()
63
64 sob = getattr(portal, obId, None)
65
66 if sob is None :
67 return False
68 elif not(sob.aq_inner.aq_self is ob.aq_inner.aq_self) :
69 return False
70 else :
71 try :
72 portal._checkId(obId)
73 return True
74 except BadRequest :
75 return False
76
77 security.declarePublic('listActionProviders_')
78 def listActionProviders_(context) :
79 atool = getToolByName(context, 'portal_actions')
80 return atool.listActionProviders()
81
82 def capitalizeCompoundGivenName(givenName) :
83 givenName = givenName.strip()
84 givenNames = ' '.join(givenName.split('-')).split()
85 givenNameCapitalized = '-'.join(map(string.capitalize, givenNames))
86 return givenNameCapitalized
87
88
89 def formatFullName(memberName, memberGivenName, memberId, nameBefore=1) :
90 memberName = memberName.decode('utf-8')
91 memberGivenName = memberGivenName.decode('utf-8')
92 memberFullName = u''
93 if memberName and memberGivenName :
94 if nameBefore :
95 memberFullName = memberName.upper() + ' ' + capitalizeCompoundGivenName(memberGivenName)
96 else :
97 memberFullName = capitalizeCompoundGivenName(memberGivenName) + ' ' + memberName.upper()
98
99 elif memberName and not memberGivenName :
100 memberFullName = memberName.upper()
101
102 elif not memberName and memberGivenName :
103 memberFullName = capitalizeCompoundGivenName(memberGivenName)
104
105 else :
106 memberFullName = memberId
107
108 return memberFullName.encode('utf-8')
109
110 # from OFS.ObjectManager #63
111 bad_url_chars = re.compile(r'[^a-zA-Z0-9-_~,.$\(\)@]')
112
113 security.declarePublic('makeValidId')
114 def makeValidId(self, id, allow_dup=0):
115 id = Utf8Utils.desacc(id)
116 id = bad_url_chars.sub('-', id)
117 # If allow_dup is false, an error will be raised if an object
118 # with the given id already exists. If allow_dup is true,
119 # only check that the id string contains no illegal chars;
120 # check_valid_id() will be called again later with allow_dup
121 # set to false before the object is added.
122
123 makeRandomId = False
124 if id in ('.', '..'):
125 makeRandomId = True
126 if id.startswith('_'):
127 id = id.lstrip('_')
128 if id.startswith('aq_'):
129 id = id[3:]
130
131 while id.endswith('__') :
132 id = id[:-1]
133 if not allow_dup:
134 obj = getattr(self, id, None)
135 if obj is not None:
136 # An object by the given id exists either in this
137 # ObjectManager or in the acquisition path.
138 flags = getattr(obj, '__replaceable__', NOT_REPLACEABLE)
139 if hasattr(aq_base(self), id):
140 # The object is located in this ObjectManager.
141 if not flags & REPLACEABLE:
142 makeRandomId = True
143 # else the object is replaceable even if the UNIQUE
144 # flag is set.
145 elif flags & UNIQUE:
146 makeRandomId = True
147 if id == 'REQUEST':
148 makeRandomId = True
149
150 if makeRandomId is True :
151 id = str(randrange(2,10000)) + id
152 return id
153
154
155
156 def _checkMemberPermission(userid, permission, obj, StringType = type('')):
157 user = obj.aq_inner.acl_users.getUser(userid)
158 roles = rolesForPermissionOn(permission, obj)
159 if type(roles) is StringType:
160 roles=[roles]
161 if user.allowed( obj, roles ):
162 return 1
163 return 0
164
165 def getCPInfo(self) :
166 try: cp = _cb_decode(self.REQUEST['__cp'])
167 except: return None
168 return cp
169
170
171 def popCP(self, indexes=None) :
172 try: cp = _cb_decode(self.REQUEST['__cp'])
173 except: return
174
175 paths = list(cp[1])
176 if indexes is not None :
177 indexes = list(indexes)
178 indexes.sort()
179 indexes.reverse()
180 for index in indexes :
181 paths.pop(index)
182 else :
183 paths.pop()
184
185 if not paths :
186 self.REQUEST.RESPONSE.expireCookie('__cp', path=self.REQUEST['BASEPATH1'] or "/")
187 else :
188 paths = tuple(paths)
189 cp = _cb_encode( (cp[0], paths) )
190 resp = self.REQUEST['RESPONSE']
191 resp.setCookie('__cp', cp, path='%s' % cookie_path(self.REQUEST))
192
193 security.declarePublic('Message')
194 Message = MessageFactory('plinn')
195
196 security.declarePublic('translate')
197 def translate(message, context):
198 """ Translate i18n message.
199 """
200 if isinstance(message, Exception):
201 try:
202 message = message[0]
203 except (TypeError, IndexError):
204 pass
205 return i18ntranslate(message, domain='plinn', context=context.REQUEST)
206
207 security.declarePublic('desacc')
208 desacc = Utf8Utils.desacc
209
210 security.declarePublic('getPreferredLanguages')
211 def getPreferredLanguages(context):
212 """ returns browser prefered languages"""
213 request = getattr(context, 'REQUEST', None)
214 if request is not None :
215 adapter = IUserPreferredLanguages(request, None)
216 if adapter is not None :
217 return adapter.getPreferredLanguages()
218 return []
219
220 security.declarePublic('getBestTranslationLanguage')
221 def getBestTranslationLanguage(langs, context):
222 """ returns best translation language according
223 availables languages (param langs)
224 and user preferences (retrieves by context)
225 """
226 request = getattr(context, 'REQUEST', None)
227 if request :
228 negociator = getUtilityByInterfaceName('zope.i18n.interfaces.INegotiator')
229 return negociator.getLanguage(langs, request) or langs[0]
230 else :
231 return langs[0]
232
233 security.declarePublic('getAdapterByInterface')
234 def getAdapterByInterface(ob, dotted_name, default=_marker) :
235 """ Get the adapter which provides the interface on the given object.
236 """
237 try:
238 iface = resolve_dotted_name(dotted_name)
239 except ImportError:
240 if default is _marker:
241 raise ComponentLookupError, dotted_name
242 return default
243
244 adapter = queryAdapter(ob, iface, default=default)
245 if adapter is _marker :
246 raise ComponentLookupError, "no adapter providing %r found on %r" % (dotted_name, ob)
247
248 # the adapter must be wrapped to allow security mahinery to work.
249 if adapter != default :
250 return adapter.__of__(ob)
251 else :
252 return default
253
254 def _sudo(func, userid=None) :
255 """
256 execute func or any callable object
257 without restriction. Used to switch off
258 security assertions (eg. checkPermission) encountered
259 during the execution.
260 """
261
262 sm = getSecurityManager()
263 restrictedUser = sm.getUser()
264
265 if not userid :
266 userid = restrictedUser.getId()
267
268 sm._context.user = UnrestrictedUser(userid, '', (), ())
269
270 deferedEx = None
271 try :
272 ret = func()
273 except Exception, e :
274 deferedEx = e
275
276 sm._context.user = restrictedUser
277
278 if deferedEx is not None :
279 raise e
280
281 return ret
282