1

我发现了 Plone 的 RegistrationTool 和 PasswordResetTool 的问题

即使没有发出 HTTPRequest,也会呈现模板 mail_password_response.pt。该模板是一个依赖于 main_template 的全帧 Plone 页面。main_template 具有依赖于真实 HTTPRequest 对象的存在的 viewlet,即其 ACTUAL_URL 参数。

如何解决这种情况?显然,如果没有浏览器来显示结果,则不应呈现 mail_password_response.pt。但是如何在深层 Plone 代码中检查 HTTPRequest 是否是“真实的”,这应该屈服于 UI 响应,比如可怕的 ZMI manage_xxx hacks?

解决这个问题的正确方法是什么?是让 RegistrationTool 不呈现模板还是让 viewlet 对不完整的测试存根 HTTPRequest 对象安全?

这是在 palayout.viewlets.common 中需要 ACTUAL_URL 的 viewlets 位

class ContentViewsViewlet(ViewletBase):


    @memoize
    def prepareObjectTabs(self, default_tab='view', sort_first=['folderContents']):
        """Prepare the object tabs by determining their order and working
        out which tab is selected. Used in global_contentviews.pt
        """
        context = aq_inner(self.context)
        context_url = context.absolute_url()

        request_url = self.request['ACTUAL_URL']
        request_url_path = request_url[len(context_url):]

        if request_url_path.startswith('/'):
            request_url_path = request_url_path[1:]

这是 CMFPlone RegistrationTool 中的违规调用,main_template.pt即使没有消费者,它也会触发渲染完整:

security.declarePublic('registeredNotify')
def registeredNotify(self, new_member_id):
    """ Wrapper around registeredNotify """
    membership = getToolByName(self, 'portal_membership')
    utils = getToolByName(self, 'plone_utils')
    member = membership.getMemberById(new_member_id)

    ...

    return self.mail_password_response(self, self.REQUEST)

示例回溯:

  Error in test test_logout_smartcard (xxxtesting.ui.test_smartcard.TestSmartcard)
    Traceback (most recent call last):
      File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/unittest/case.py", line 318, in run
        self.setUp()
      File "/Users/mikko/code/xxx-dev/src/xxx-packages/xxxtesting/xxxtesting/ui/test_smartcard.py", line 193, in setUp
        self.xxx_helper.create_all()
      File "/Users/mikko/code/xxx-dev/src/xxx-packages/xxxtesting/xxxtesting/xxxhelper.py", line 594, in create_all
        self.create_xxx_manager("xxx_manager")
      File "/Users/mikko/code/xxx-dev/src/xxx-packages/xxxtesting/xxxtesting/xxxhelper.py", line 412, in create_xxx_manager
        mem.update(**data)
      File "/Users/mikko/code/buildout-cache/eggs/Products.remember-1.9.1-py2.7.egg/Products/remember/content/member.py", line 653, in update
        triggerAutomaticTransitions(self)
      File "/Users/mikko/code/buildout-cache/eggs/Products.remember-1.9.1-py2.7.egg/Products/remember/Extensions/workflow.py", line 34, in triggerAutomaticTransitions
        wf_tool.doActionFor(ob, 'trigger')
      File "/Users/mikko/code/buildout-cache/eggs/Products.CMFCore-2.2.6-py2.7.egg/Products/CMFCore/WorkflowTool.py", line 241, in doActionFor
        wfs, ob, action, wf.doActionFor, (ob, action) + args, kw)
      File "/Users/mikko/code/buildout-cache/eggs/Products.CMFCore-2.2.6-py2.7.egg/Products/CMFCore/WorkflowTool.py", line 552, in _invokeWithNotification
        res = func(*args, **kw)
      File "/Users/mikko/code/buildout-cache/eggs/Products.DCWorkflow-2.2.4-py2.7.egg/Products/DCWorkflow/DCWorkflow.py", line 282, in doActionFor
        self._changeStateOf(ob, tdef, kw)
      File "/Users/mikko/code/buildout-cache/eggs/Products.DCWorkflow-2.2.4-py2.7.egg/Products/DCWorkflow/DCWorkflow.py", line 421, in _changeStateOf
        sdef = self._executeTransition(ob, tdef, kwargs)
      File "/Users/mikko/code/buildout-cache/eggs/Products.DCWorkflow-2.2.4-py2.7.egg/Products/DCWorkflow/DCWorkflow.py", line 474, in _executeTransition
        script(sci)  # May throw an exception.
      File "/Users/mikko/code/buildout-cache/eggs/Products.ExternalMethod-2.13.0-py2.7.egg/Products/ExternalMethod/ExternalMethod.py", line 241, in __call__
        return f(self.aq_parent.this(), *args, **kw)
       - __traceback_info__: ((<Products.DCWorkflow.Expression.StateChangeInfo instance at 0x107492e18>,), {}, None)
      File "/Users/mikko/code/buildout-cache/eggs/Products.remember-1.9.1-py2.7.egg/Products/remember/Extensions/workflow.py", line 64, in register
        return obj.register()
      File "/Users/mikko/code/xxx-dev/src/xxx-eggs/Products.xxxHospital/Products/xxxHospital/content/xxxUser.py", line 194, in register
        BaseMember.register(self)
      File "/Users/mikko/code/buildout-cache/eggs/Products.remember-1.9.1-py2.7.egg/Products/remember/content/member.py", line 718, in register
        rtool.registeredNotify(self.getId())
      File "/Users/mikko/code/buildout-cache/eggs/Products.CMFPlone-4.1.6-py2.7.egg/Products/CMFPlone/RegistrationTool.py", line 345, in registeredNotify
        return self.mail_password_response(self, self.REQUEST)
      File "/Users/mikko/code/buildout-cache/eggs/Zope2-2.13.15-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.15-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.15-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 954, in do_defineSlot
        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 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 858, in do_defineMacro
        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 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 742, in do_insertStructure_tal
        structure = self.engine.evaluateStructure(expr)
      File "/Users/mikko/code/buildout-cache/eggs/Zope2-2.13.15-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.2-py2.7.egg/zope/tales/tales.py", line 696, in evaluate
        return expression(self)
       - file:/Users/mikko/code/xxx-dev/src/xxx-packages/plonetheme.xxxexternal/plonetheme/xxxexternal/skins/plonetheme_xxxexternal_custom_templates/main_template.pt
       - Line 83, Column 20
       - Expression: <StringExpr u'plone.contentviews'>
       - Names:
          {'container': <PloneSite at /plone>,
           'context': <RegistrationTool at /plone/portal_registration used for /plone/portal_memberdata/xxx_manager>,
           'default': <object object at 0x10204e970>,
           'here': <RegistrationTool at /plone/portal_registration used for /plone/portal_memberdata/xxx_manager>,
           'loop': {},
           'nothing': None,
           'options': {'args': (<RegistrationTool at /plone/portal_registration used for /plone/portal_memberdata/xxx_manager>,
                                <HTTPRequest, URL=http://localhost:55001>)},
           'repeat': <Products.PageTemplates.Expressions.SafeMapping object at 0x107704c00>,
           'request': <HTTPRequest, URL=http://localhost:55001>,
           'root': <Application at >,
           'template': <FSPageTemplate at /plone/mail_password_response used for /plone/portal_registration>,
           'traverse_subpath': [],
           'user': <PloneUser 'admin'>}
      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/plone.app.layout-2.1.13-py2.7.egg/plone/app/layout/viewlets/common.py", line 48, in render
        return self.index()
      File "/Users/mikko/code/buildout-cache/eggs/Zope2-2.13.15-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.15-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 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 583, in do_setLocal_tal
        self.engine.setLocal(name, self.engine.evaluateValue(expr))
      File "/Users/mikko/code/buildout-cache/eggs/zope.tales-3.5.2-py2.7.egg/zope/tales/tales.py", line 696, in evaluate
        return expression(self)
       - /Users/mikko/code/buildout-cache/eggs/plone.app.layout-2.1.13-py2.7.egg/plone/app/layout/viewlets/contentviews.pt
       - Line 6, Column 4
       - Expression: <PathExpr standard:u'view/prepareObjectTabs'>
       - Names:
          {'args': (),
           'container': <RegistrationTool at /plone/portal_registration used for /plone/portal_memberdata/xxx_manager>,
           'context': <RegistrationTool at /plone/portal_registration used for /plone/portal_memberdata/xxx_manager>,
           'default': <object object at 0x10204e970>,
           'here': <RegistrationTool at /plone/portal_registration used for /plone/portal_memberdata/xxx_manager>,
           'loop': {},
           'nothing': None,
           'options': {},
           'repeat': <Products.PageTemplates.Expressions.SafeMapping object at 0x107afe050>,
           'request': <HTTPRequest, URL=http://localhost:55001>,
           'root': <Application at >,
           'template': <Products.Five.browser.pagetemplatefile.ViewPageTemplateFile object at 0x105dfb810>,
           'traverse_subpath': [],
           'user': <PloneUser 'admin'>,
           'view': <Products.Five.viewlet.metaconfigure.ContentViewsViewlet object at 0x10868c050>,
           'views': <Products.Five.browser.pagetemplatefile.ViewMapper object at 0x107ff1f90>}
      File "/Users/mikko/code/buildout-cache/eggs/zope.tales-3.5.2-py2.7.egg/zope/tales/expressions.py", line 217, in __call__
        return self._eval(econtext)
      File "/Users/mikko/code/buildout-cache/eggs/Zope2-2.13.15-py2.7.egg/Products/PageTemplates/Expressions.py", line 155, in _eval
        return render(ob, econtext.vars)
      File "/Users/mikko/code/buildout-cache/eggs/Zope2-2.13.15-py2.7.egg/Products/PageTemplates/Expressions.py", line 117, in render
        ob = ob()
      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/viewlets/common.py", line 258, in prepareObjectTabs
        request_url = self.request['ACTUAL_URL']
      File "/Users/mikko/code/buildout-cache/eggs/Zope2-2.13.15-py2.7.egg/ZPublisher/HTTPRequest.py", line 1372, in __getitem__
        raise KeyError, key
    KeyError: 'ACTUAL_URL'
4

0 回答 0