Ticket #13133 (confirmed Bug)
CMFCore breaks if entering a portal_actions action with non-ASCII letters
Reported by: | miohtama | Owned by: | |
---|---|---|---|
Priority: | minor | Milestone: | 4.x |
Component: | Backend (Python) | Version: | 4.1 |
Keywords: | patch, upstream | Cc: |
Description
I am not sure where to report this bug, so please guide forward.
- plone.app.layout.globals.context Context Helper has IContextState.actions() method
- If you enter a new portal_actions action through ZMI containing non-ascii letters this method breaks down
- Apparently the bug might be deeper in CMFCore which does not correctly handle non-ASCII action titles
OR
- portal_actions ZMI save form handles non-ASCII data wrong
Steps to repeat
1) Create a new action category in portal_actions
2) Add an action with non-ASCII character in a title
3) Call @@plone_context_helper.actions() for this new category
Traceback:
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 1: ordinal not in range(128) 2012-08-27 19:55:59 INFO collective.logbook handle traceback [http://localhost:9966/Plone/error_log/showEntry?id=1346086558.850.921704120859] 2012-08-27 19:55:59 ERROR root Exception while rendering an error message Traceback (most recent call last): File "/Users/mikko/code/buildout-cache/eggs/Zope2-2.13.13-py2.7.egg/OFS/SimpleItem.py", line 242, in raise_standardErrorMessage v = s(**kwargs) File "/Users/mikko/code/buildout-cache/eggs/Products.CMFCore-2.2.6-py2.7.egg/Products/CMFCore/FSPythonScript.py", line 127, in __call__ return Script.__call__(self, *args, **kw) File "/Users/mikko/code/buildout-cache/eggs/Zope2-2.13.13-py2.7.egg/Shared/DC/Scripts/Bindings.py", line 322, in __call__ return self._bindAndExec(args, kw, None) File "/Users/mikko/code/buildout-cache/eggs/Zope2-2.13.13-py2.7.egg/Shared/DC/Scripts/Bindings.py", line 359, in _bindAndExec return self._exec(bound_data, args, kw) File "/Users/mikko/code/buildout-cache/eggs/Products.PythonScripts-2.13.0-py2.7.egg/Products/PythonScripts/PythonScript.py", line 344, in _exec result = f(*args, **kw) File "Script (Python)", line 34, in standard_error_message File "/Users/mikko/code/buildout-cache/eggs/Zope2-2.13.13-py2.7.egg/Shared/DC/Scripts/Bindings.py", line 322, in __call__ return self._bindAndExec(args, kw, None) File "/Users/mikko/code/buildout-cache/eggs/Zope2-2.13.13-py2.7.egg/Shared/DC/Scripts/Bindings.py", line 359, in _bindAndExec return self._exec(bound_data, args, kw) File "/Users/mikko/code/buildout-cache/eggs/Products.CMFCore-2.2.6-py2.7.egg/Products/CMFCore/FSPageTemplate.py", line 237, in _exec result = self.pt_render(extra_context=bound_names) File "/Users/mikko/code/buildout-cache/eggs/Products.CMFCore-2.2.6-py2.7.egg/Products/CMFCore/FSPageTemplate.py", line 177, in pt_render self, source, extra_context File "/Users/mikko/code/buildout-cache/eggs/Zope2-2.13.13-py2.7.egg/Products/PageTemplates/PageTemplate.py", line 79, in pt_render showtal=showtal) File "/Users/mikko/code/buildout-cache/eggs/zope.pagetemplate-3.5.2-py2.7.egg/zope/pagetemplate/pagetemplate.py", line 113, in pt_render strictinsert=0, sourceAnnotations=sourceAnnotations)() File "/Users/mikko/code/buildout-cache/eggs/zope.tal-3.5.2-py2.7.egg/zope/tal/talinterpreter.py", line 271, in __call__ self.interpret(self.program) File "/Users/mikko/code/buildout-cache/eggs/zope.tal-3.5.2-py2.7.egg/zope/tal/talinterpreter.py", line 343, in interpret handlers[opcode](self, args) File "/Users/mikko/code/buildout-cache/eggs/zope.tal-3.5.2-py2.7.egg/zope/tal/talinterpreter.py", line 888, in do_useMacro self.interpret(macro) File "/Users/mikko/code/buildout-cache/eggs/zope.tal-3.5.2-py2.7.egg/zope/tal/talinterpreter.py", line 343, in interpret handlers[opcode](self, args) File "/Users/mikko/code/buildout-cache/eggs/zope.tal-3.5.2-py2.7.egg/zope/tal/talinterpreter.py", line 533, in do_optTag_tal self.do_optTag(stuff) File "/Users/mikko/code/buildout-cache/eggs/zope.tal-3.5.2-py2.7.egg/zope/tal/talinterpreter.py", line 518, in do_optTag return self.no_tag(start, program) File "/Users/mikko/code/buildout-cache/eggs/zope.tal-3.5.2-py2.7.egg/zope/tal/talinterpreter.py", line 513, in no_tag self.interpret(program) File "/Users/mikko/code/buildout-cache/eggs/zope.tal-3.5.2-py2.7.egg/zope/tal/talinterpreter.py", line 343, in interpret handlers[opcode](self, args) File "/Users/mikko/code/buildout-cache/eggs/zope.tal-3.5.2-py2.7.egg/zope/tal/talinterpreter.py", line 852, in do_condition self.interpret(block) File "/Users/mikko/code/buildout-cache/eggs/zope.tal-3.5.2-py2.7.egg/zope/tal/talinterpreter.py", line 343, in interpret handlers[opcode](self, args) File "/Users/mikko/code/buildout-cache/eggs/zope.tal-3.5.2-py2.7.egg/zope/tal/talinterpreter.py", line 531, in do_optTag_tal self.no_tag(stuff[-2], stuff[-1]) File "/Users/mikko/code/buildout-cache/eggs/zope.tal-3.5.2-py2.7.egg/zope/tal/talinterpreter.py", line 513, in no_tag self.interpret(program) File "/Users/mikko/code/buildout-cache/eggs/zope.tal-3.5.2-py2.7.egg/zope/tal/talinterpreter.py", line 343, in interpret handlers[opcode](self, args) File "/Users/mikko/code/buildout-cache/eggs/zope.tal-3.5.2-py2.7.egg/zope/tal/talinterpreter.py", line 742, in do_insertStructure_tal structure = self.engine.evaluateStructure(expr) File "/Users/mikko/code/buildout-cache/eggs/Zope2-2.13.13-py2.7.egg/Products/PageTemplates/Expressions.py", line 218, in evaluateStructure text = super(ZopeContext, self).evaluateStructure(expr) File "/Users/mikko/code/buildout-cache/eggs/zope.tales-3.5.1-py2.7.egg/zope/tales/tales.py", line 696, in evaluate return expression(self) File "/Users/mikko/code/buildout-cache/eggs/zope.contentprovider-3.7.2-py2.7.egg/zope/contentprovider/tales.py", line 80, in __call__ return provider.render() File "/Users/mikko/code/buildout-cache/eggs/plone.app.viewletmanager-2.0.2-py2.7.egg/plone/app/viewletmanager/manager.py", line 154, in render return BaseOrderedViewletManager.render(self) File "/Users/mikko/code/buildout-cache/eggs/plone.app.viewletmanager-2.0.2-py2.7.egg/plone/app/viewletmanager/manager.py", line 85, in render return u'\n'.join([viewlet.render() for viewlet in self.viewlets]) File "/Users/mikko/code/buildout-cache/eggs/zope.browserpage-3.12.2-py2.7.egg/zope/browserpage/simpleviewclass.py", line 44, in __call__ return self.index(*args, **kw) File "/Users/mikko/code/buildout-cache/eggs/Zope2-2.13.13-py2.7.egg/Products/Five/browser/pagetemplatefile.py", line 125, in __call__ return self.im_func(im_self, *args, **kw) File "/Users/mikko/code/buildout-cache/eggs/Zope2-2.13.13-py2.7.egg/Products/Five/browser/pagetemplatefile.py", line 59, in __call__ sourceAnnotations=getattr(debug_flags, 'sourceAnnotations', 0), File "/Users/mikko/code/buildout-cache/eggs/zope.pagetemplate-3.5.2-py2.7.egg/zope/pagetemplate/pagetemplate.py", line 113, in pt_render strictinsert=0, sourceAnnotations=sourceAnnotations)() File "/Users/mikko/code/buildout-cache/eggs/zope.tal-3.5.2-py2.7.egg/zope/tal/talinterpreter.py", line 271, in __call__ self.interpret(self.program) File "/Users/mikko/code/buildout-cache/eggs/zope.tal-3.5.2-py2.7.egg/zope/tal/talinterpreter.py", line 343, in interpret handlers[opcode](self, args) File "/Users/mikko/code/buildout-cache/eggs/zope.tal-3.5.2-py2.7.egg/zope/tal/talinterpreter.py", line 531, in do_optTag_tal self.no_tag(stuff[-2], stuff[-1]) File "/Users/mikko/code/buildout-cache/eggs/zope.tal-3.5.2-py2.7.egg/zope/tal/talinterpreter.py", line 513, in no_tag self.interpret(program) File "/Users/mikko/code/buildout-cache/eggs/zope.tal-3.5.2-py2.7.egg/zope/tal/talinterpreter.py", line 343, in interpret handlers[opcode](self, args) File "/Users/mikko/code/buildout-cache/eggs/zope.tal-3.5.2-py2.7.egg/zope/tal/talinterpreter.py", line 742, in do_insertStructure_tal structure = self.engine.evaluateStructure(expr) File "/Users/mikko/code/buildout-cache/eggs/Zope2-2.13.13-py2.7.egg/Products/PageTemplates/Expressions.py", line 218, in evaluateStructure text = super(ZopeContext, self).evaluateStructure(expr) File "/Users/mikko/code/buildout-cache/eggs/zope.tales-3.5.1-py2.7.egg/zope/tales/tales.py", line 696, in evaluate return expression(self) File "/Users/mikko/code/buildout-cache/eggs/zope.contentprovider-3.7.2-py2.7.egg/zope/contentprovider/tales.py", line 77, in __call__ provider.update() File "/Users/mikko/code/buildout-cache/eggs/zope.viewlet-3.7.2-py2.7.egg/zope/viewlet/manager.py", line 112, in update self._updateViewlets() File "/Users/mikko/code/buildout-cache/eggs/zope.viewlet-3.7.2-py2.7.egg/zope/viewlet/manager.py", line 118, in _updateViewlets viewlet.update() File "/Users/mikko/code/xxx/src/plomobile/plomobile/viewlets.py", line 45, in update self.quick_links = context_state.actions("mobile_quick_links") # id -> action mappings File "/Users/mikko/code/buildout-cache/eggs/plone.memoize-1.1.1-py2.7.egg/plone/memoize/view.py", line 47, in memogetter value = cache[key] = func(*args, **kwargs) File "/Users/mikko/code/buildout-cache/eggs/plone.app.layout-2.1.13-py2.7.egg/plone/app/layout/globals/context.py", line 237, in actions max=max, File "/Users/mikko/code/buildout-cache/eggs/Products.CMFPlone-4.1.5-py2.7.egg/Products/CMFPlone/ActionsTool.py", line 56, in listActionInfos actions = [ActionInfo(action, ec) for action in actions] File "/Users/mikko/code/buildout-cache/eggs/Products.CMFCore-2.2.6-py2.7.egg/Products/CMFCore/ActionInformation.py", line 190, in __init__ (lazy_map, lazy_keys) = action.getInfoData() File "/Users/mikko/code/buildout-cache/eggs/Products.CMFCore-2.2.6-py2.7.egg/Products/CMFCore/ActionInformation.py", line 156, in getInfoData val = Message(val, self.i18n_domain) UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 1: ordinal not in range(128)
Change History
comment:2 Changed 4 years ago by miohtama
Here is a monkey-patch to issue (I don't have Zope commit rights nor aware of the process):
from Acquisition import aq_base, aq_inner, aq_parent from zope.i18nmessageid import Message from Products.CMFCore.ActionInformation import Action # # Fix implicit assumption that actions titles are unicode strings or ASCII strings # -> action titles entered through ZMI have utf-8 encoding # def getInfoData(self): """ Get the data needed to create an ActionInfo. """ category_path = [] lazy_keys = [] lazy_map = {} lazy_map['id'] = self.getId() parent = aq_parent(self) while parent is not None and parent.getId() != 'portal_actions': category_path.append( parent.getId()) parent = aq_parent(parent) lazy_map['category'] = '/'.join(category_path[::-1]) for id, val in self.propertyItems(): if type(val) == str: val = val.decode("utf-8") if id.endswith('_expr'): id = id[:-5] if val: val = getattr(self, '%s_expr_object' % id) lazy_keys.append(id) elif id == 'available': val = True elif id == 'i18n_domain': continue elif id == 'link_target': val = val or None elif self.i18n_domain and id in ('title', 'description'): val = Message(val, self.i18n_domain) lazy_map[id] = val return (lazy_map, lazy_keys) Action.getInfoData = getInfoData
Note: See
TracTickets for help on using
tickets.