Ticket #13133 (confirmed Bug)

Opened 4 years ago

Last modified 4 years ago

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:1 Changed 4 years ago by kleist

  • Status changed from new to confirmed

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

comment:3 Changed 4 years ago by kleist

  • Keywords patch, upstream added
Note: See TracTickets for help on using tickets.