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