检查HTTPRequest是否为;“真正的”;或者我们正在Plone中运行headless(单元测试)

检查HTTPRequest是否为;“真正的”;或者我们正在Plone中运行headless(单元测试),plone,Plone,我发现Plone的注册工具和密码重置工具有问题 即使未进行HTTPRequest,也会呈现Template mail_password_response.pt。此模板是一个全帧Plone页面,依赖于主模板。main_模板有viewlets,它依赖于真实HTTPRequest对象的存在,即它的实际_URL参数 如何解决这种情况?显然,如果没有浏览器显示结果,则不应呈现mail_password_response.pt。但是,如何在深层Plone代码中检查HTTPRequest是否是“真实”的

我发现Plone的注册工具和密码重置工具有问题

即使未进行HTTPRequest,也会呈现Template mail_password_response.pt。此模板是一个全帧Plone页面,依赖于主模板。main_模板有viewlets,它依赖于真实HTTPRequest对象的存在,即它的实际_URL参数

如何解决这种情况?显然,如果没有浏览器显示结果,则不应呈现mail_password_response.pt。但是,如何在深层Plone代码中检查HTTPRequest是否是“真实”的,从而让用户界面响应更糟糕?ZMI manage_xxx hacks

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

这是p.a.layout.viewlets.common中需要实际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'
测试注销智能卡(xxxtesting.ui.test\u smartcard.TestSmartcard)中出现错误 回溯(最近一次呼叫最后一次): 文件“/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/unittest/case.py”,第318行,运行中 self.setUp() 文件“/Users/mikko/code/xxx dev/src/xxx packages/xxxtesting/xxxtesting/ui/test\u smartcard.py”,第193行,在安装程序中 self.xxx\u helper.create\u all() 文件“/Users/mikko/code/xxx dev/src/xxx packages/xxxtesting/xxxtesting/xxxhelper.py”,第594行,在create_all中 自行创建xxx经理(“xxx经理”) 文件“/Users/mikko/code/xxx dev/src/xxx packages/xxxtesting/xxxtesting/xxxhelper.py”,第412行,在创建xxx管理器中 成员更新(**数据) 文件“/Users/mikko/code/buildout cache/eggs/Products.memory-1.9.1-py2.7.egg/Products/memory/content/member.py”,第653行,在更新中 触发器自动转换(自) 文件“/Users/mikko/code/buildout cache/eggs/Products.memory-1.9.1-py2.7.egg/Products/memory/Extensions/workflow.py”,第34行,在triggerAutomaticTransitions中 wf_tool.doActionFor(ob,'触发器') 文件“/Users/mikko/code/buildout cache/eggs/Products.CMFCore-2.2.6-py2.7.egg/Products/CMFCore/WorkflowTool.py”,第241行,在doActionFor中 wfs,ob,action,wf.doActionFor,(ob,action)+args,kw) 文件“/Users/mikko/code/buildout cache/eggs/Products.CMFCore-2.2.6-py2.7.egg/Products/CMFCore/WorkflowTool.py”,第552行,在_invokeWithNotification中 res=func(*参数,**kw) doActionFor中的文件“/Users/mikko/code/buildout cache/eggs/Products.DCWorkflow-2.2.4-py2.7.egg/Products/DCWorkflow/DCWorkflow.py”,第282行 自转换状态(ob、tdef、kw) 文件“/Users/mikko/code/buildout cache/eggs/Products.DCWorkflow-2.2.4-py2.7.egg/Products/DCWorkflow/DCWorkflow.py”,第421行,位于 sdef=自我执行转换(ob、tdef、kwargs) 文件“/Users/mikko/code/buildout cache/eggs/Products.DCWorkflow-2.2.4-py2.7.egg/Products/DCWorkflow/DCWorkflow.py”,第474行,在执行转换中 脚本(sci)#可能引发异常。 文件“/Users/mikko/code/buildout cache/eggs/Products.ExternalMethod-2.13.0-py2.7.egg/Products/ExternalMethod/ExternalMethod.py”,调用中第241行__ 返回f(self.aq_parent.this(),*args,**kw) -回溯信息:((,),{},无) 文件“/Users/mikko/code/buildout cache/eggs/Products.memory-1.9.1-py2.7.egg/Products/memory/Extensions/workflow.py”,第64行,在注册表中 返回对象寄存器() 文件“/Users/mikko/code/xxx-dev/src/xxx-eggs/Products.xxxHospital/Products/xxxHospital/content/xxxUser.py”,第194行,在注册表中 BaseMember.register(self) 文件“/Users/mikko/code/buildout cache/eggs/Products.memory-1.9.1-py2.7.egg/Products/memory/content/member.py”,第718行,在寄存器中 rtool.registeredNotify(self.getId()) 文件“/Users/mikko/code/buildout cache/eggs/Products.CMFPlone-4.1.6-py2.7.egg/Products/CMFPlone/RegistrationTool.py”,第345行,在registeredNotify中 返回self.mail\u密码\u响应(self,self.REQUEST) 文件“/Users/mikko/code/buildout cache/eggs/Zope2-2.13.15-py2.7.egg/Shared/DC/Scripts/Bindings.py”,第322行,in__调用__ 返回self.\u bindAndExec(参数,千瓦,无) 文件“/Users/mikko/code/buildout cache/eggs/Zope2-2.13.15-py2.7.egg/Shared/DC/Scripts/Bindings.py”,第359行,in_bindAndExec 返回self.\u exec(绑定的\u数据,参数,千瓦) 文件“/Users/mikko/code/buildout cache/eggs/Products.CMFCore-2.2.6-py2.7.egg/Products/CMFCore/FSPageTemplate.py”,第237行,在 结果=self.pt\u render(额外上下文=绑定名称) 文件“/Users/mikko/code/buildout cache/eggs/Products.CMFCore-2.2.6-py2.7.egg/Products/CMFCore/FSPageTemplate.py”,第177行,在pt_渲染中 自身、源、额外上下文 文件“/Users/mikko/code/buildout cache/eggs/Zope2-2.13.15-py2.7.egg/Products/PageTemplates/PageTemplate.py”,第79行,在pt_render中 showtal=showtal) 文件“/Users/mikko/code/buildout cache/eggs/zope.pagetemplate-3.5.2-py2.7.egg/zope/pagetemplate/pagetemplate.py”,第113行,在pt_render中 strictinsert=0,sourceAnnotations=sourceAnnotations)() 文件“/Users/mikko/code/buildout cache/eggs/zope.tal-3.5.2-py2.7.egg/zope/tal/talinterpreter.py”,第271行,在调用中__ 自我解释(self.program) 文件“/Users/mikko/code/buildout cache/eggs/zope.tal-3.5.2-py2.7.egg/zope/tal/talinterpreter.py”,第343行,在解释中 处理程序[操作码](自身,参数) 文件“/Users/mikko/code/buildout cache/eggs/zope.tal-3.5.2-py2.7.egg/zope/tal/talinterpreter.py”,第888行,在do_useMacro中 自我解释(宏) 文件“/Users/mikko/code/buildout cache/eggs/zope.tal-3.5.2