[Checkins] SVN: Products.CMFDefault/trunk/Products/CMFDefault/browser/ Add 'ursine_globals' view.

Tres Seaver tseaver at palladion.com
Mon Oct 6 23:04:22 EDT 2008


Log message for revision 91828:
  Add 'ursine_globals' view.

Changed:
  U   Products.CMFDefault/trunk/Products/CMFDefault/browser/configure.zcml
  A   Products.CMFDefault/trunk/Products/CMFDefault/browser/tests/
  A   Products.CMFDefault/trunk/Products/CMFDefault/browser/tests/__init__.py
  A   Products.CMFDefault/trunk/Products/CMFDefault/browser/tests/test_ursa.py
  A   Products.CMFDefault/trunk/Products/CMFDefault/browser/ursa.py

-=-
Modified: Products.CMFDefault/trunk/Products/CMFDefault/browser/configure.zcml
===================================================================
--- Products.CMFDefault/trunk/Products/CMFDefault/browser/configure.zcml	2008-10-07 02:58:30 UTC (rev 91827)
+++ Products.CMFDefault/trunk/Products/CMFDefault/browser/configure.zcml	2008-10-07 03:04:22 UTC (rev 91828)
@@ -136,4 +136,11 @@
       permission="zope2.View"
       />
 
+  <browser:page
+      for="*"
+      name="ursine_globals"
+      class=".ursa.UrsineGlobals"
+      permission="zope.Public"
+      />
+
 </configure>

Added: Products.CMFDefault/trunk/Products/CMFDefault/browser/tests/__init__.py
===================================================================
--- Products.CMFDefault/trunk/Products/CMFDefault/browser/tests/__init__.py	                        (rev 0)
+++ Products.CMFDefault/trunk/Products/CMFDefault/browser/tests/__init__.py	2008-10-07 03:04:22 UTC (rev 91828)
@@ -0,0 +1,5 @@
+# Unit tests for CMFDefault browser views.
+import unittest
+
+def test_suite():
+    return unittest.TestSuite()

Added: Products.CMFDefault/trunk/Products/CMFDefault/browser/tests/test_ursa.py
===================================================================
--- Products.CMFDefault/trunk/Products/CMFDefault/browser/tests/test_ursa.py	                        (rev 0)
+++ Products.CMFDefault/trunk/Products/CMFDefault/browser/tests/test_ursa.py	2008-10-07 03:04:22 UTC (rev 91828)
@@ -0,0 +1,430 @@
+##############################################################################
+#
+# Copyright (c) 2008 Zope Corporation and Contributors. All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+""" Test Products.CMFDefault.browser.ursa
+
+$Id$
+"""
+import unittest
+from zope.component.testing import PlacelessSetup
+
+class UrsineGlobalsTests(unittest.TestCase, PlacelessSetup):
+
+    def setUp(self):
+        PlacelessSetup.setUp(self)
+
+    def tearDown(self):
+        PlacelessSetup.tearDown(self)
+
+    def _getTargetClass(self):
+        from Products.CMFDefault.browser.ursa import UrsineGlobals
+        return UrsineGlobals
+
+    def _makeOne(self, context=None, request=None):
+        if context is None:
+            context = self._makeContext()
+        if request is None:
+            request = DummyRequest()
+        return self._getTargetClass()(context, request)
+
+    def _makeContext(self):
+        from zope.component import getSiteManager
+        from Products.CMFCore.interfaces import IPropertiesTool
+        context = DummyContext()
+        tool = context.portal_properties = DummyPropertiesTool()
+        sm = getSiteManager()
+        sm.registerUtility(tool, IPropertiesTool)
+        return context
+
+    def test_ctor_wo_def_charset_doesnt_set_content_type(self):
+        context = self._makeContext()
+        request = DummyRequest()
+        response = request.RESPONSE
+        view = self._makeOne(context, request)
+        self.assertEqual(len(response._set_headers), 0)
+
+    def test_ctor_w_resp_charset_doesnt_set_content_type(self):
+        context = self._makeContext()
+        request = DummyRequest()
+        response = request.RESPONSE
+        response._orig_headers['content-type'] = 'text/html; charset=UTF-8'
+        view = self._makeOne(context, request)
+        self.assertEqual(len(response._set_headers), 0)
+
+    def test_ctor_w_resp_charset_w_def_charset_doesnt_override_charset(self):
+        context = self._makeContext()
+        context.portal_properties.default_charset = 'latin1'
+        request = DummyRequest()
+        response = request.RESPONSE
+        response._orig_headers['content-type'] = 'text/html; charset=UTF-8'
+        view = self._makeOne(context, request)
+        self.assertEqual(len(response._set_headers), 0)
+
+    def test_ctor_wo_resp_charst_w_def_charset_sets_charset(self):
+        context = self._makeContext()
+        context.portal_properties.default_charset = 'latin1'
+        request = DummyRequest()
+        response = request.RESPONSE
+        response._orig_headers['content-type'] = 'text/html'
+        view = self._makeOne(context, request)
+        self.assertEqual(len(response._set_headers), 1)
+        self.assertEqual(response._set_headers[0],
+                         ('content-type', 'text/html; charset=latin1'))
+
+    def test_ptool(self):
+        view = self._makeOne()
+        tool = view.context.portal_properties
+        self.failUnless(view.ptool is tool)
+
+    def test_utool(self):
+        view = self._makeOne()
+        tool = view.context.portal_url = DummyURLTool()
+        self.failUnless(view.utool is tool)
+
+    def test_mtool(self):
+        view = self._makeOne()
+        tool = view.context.portal_membership = DummyMembershipTool()
+        self.failUnless(view.mtool is tool)
+
+    def test_atool(self):
+        view = self._makeOne()
+        tool = view.context.portal_actions = DummyActionsTool()
+        self.failUnless(view.atool is tool)
+
+    def test_wtool(self):
+        view = self._makeOne()
+        tool = view.context.portal_workflow = DummyWorkflowTool()
+        self.failUnless(view.wtool is tool)
+
+    def test_portal_object(self):
+        view = self._makeOne()
+        tool = view.context.portal_url = DummyURLTool()
+        portal = DummyContext()
+        tool.getPortalObject = lambda: portal
+        self.failUnless(view.portal_object is portal)
+
+    def test_portal_url(self):
+        view = self._makeOne()
+        tool = view.context.portal_url = DummyURLTool()
+        tool.__call__ = lambda: 'http://example.com/'
+        self.assertEqual(view.portal_url, 'http://example.com/')
+
+    def test_portal_title(self):
+        view = self._makeOne()
+        tool = view.context.portal_url = DummyURLTool()
+        portal = DummyContext()
+        portal.Title = lambda: 'TITLE'
+        tool.getPortalObject = lambda: portal
+        self.assertEqual(view.portal_title, 'TITLE')
+
+    def test_object_title(self):
+        view = self._makeOne()
+        view.context.Title = lambda: 'TITLE'
+        self.assertEqual(view.object_title, 'TITLE')
+
+    def test_object_description(self):
+        view = self._makeOne()
+        view.context.Title = lambda: 'TITLE'
+        self.assertEqual(view.object_title, 'TITLE')
+
+    def test_trunc_id(self):
+        view = self._makeOne()
+        view.context.getId = lambda: 'ID'
+        self.assertEqual(view.trunc_id, 'ID')
+
+    def test_trunc_id_w_long_id(self):
+        view = self._makeOne()
+        view.context.getId = lambda: 'X' * 20
+        self.assertEqual(view.trunc_id, 'X' * 15 + '...')
+
+    def test_icon_wo_getIcon_w_icon(self):
+        view = self._makeOne()
+        view.context.getIcon = lambda: 'ICON'
+        view.context.icon = 'ICON2'
+        self.assertEqual(view.icon, 'ICON')
+
+    def test_icon_wo_getIcon_w_icon(self):
+        view = self._makeOne()
+        view.context.icon = 'ICON'
+        self.assertEqual(view.icon, 'ICON')
+
+    def test_icon_wo_getIcon_wo_icon(self):
+        view = self._makeOne()
+        self.assertEqual(view.icon, '')
+
+    def test_typename(self):
+        view = self._makeOne()
+        view.context.getPortalTypeName = lambda: 'TYPENAME'
+        self.assertEqual(view.typename, 'TYPENAME')
+
+    def test_wf_state(self):
+        view = self._makeOne()
+        view.context.portal_workflow = DummyWorkflowTool()
+        self.assertEqual(view.wf_state, 'DUMMY')
+
+    def test_page_title_wo_match(self):
+        view = self._makeOne()
+        view.context.Title = lambda: 'CONTEXT'
+        tool = view.context.portal_url = DummyURLTool()
+        portal = DummyContext()
+        portal.Title = lambda: 'SITE'
+        tool.getPortalObject = lambda: portal
+        self.assertEqual(view.page_title, 'SITE: CONTEXT')
+
+    def test_page_title_w_match(self):
+        view = self._makeOne()
+        view.context.Title = lambda: 'MATCH'
+        tool = view.context.portal_url = DummyURLTool()
+        portal = DummyContext()
+        portal.Title = lambda: 'MATCH'
+        tool.getPortalObject = lambda: portal
+        self.assertEqual(view.page_title, 'MATCH')
+
+    def test_breadcrumbs_at_root(self):
+        PATHS_TO_CONTEXTS = []
+        site = DummySite(PATHS_TO_CONTEXTS)
+        ptool = site.portal_properties = DummyPropertiesTool()
+        ptool.title = lambda: 'SITE'
+        utool = site.portal_url = DummyURLTool(site, PATHS_TO_CONTEXTS)
+        utool.__call__ = lambda: 'http://example.com/'
+        view = self._makeOne(context=site)
+        crumbs = view.breadcrumbs
+        self.assertEqual(len(crumbs), 1)
+        self.assertEqual(crumbs[0]['id'], 'root')
+        self.assertEqual(crumbs[0]['title'], 'SITE')
+        self.assertEqual(crumbs[0]['url'], 'http://example.com/')
+
+    def test_breadcrumbs_not_root(self):
+        context = DummyContext()
+        context.Title = lambda: 'CONTEXT'
+        context.absolute_url = lambda: 'http://example.com/parent/child'
+        parent = DummyContext()
+        parent.Title = lambda: 'PARENT'
+        parent.absolute_url = lambda: 'http://example.com/parent'
+        PATHS_TO_CONTEXTS = [(('parent',), parent),
+                             (('parent', 'child'), context),
+                            ]
+        site = DummySite(PATHS_TO_CONTEXTS)
+        ptool = context.portal_properties = DummyPropertiesTool()
+        ptool.title = lambda: 'SITE'
+        utool = context.portal_url = DummyURLTool(site, PATHS_TO_CONTEXTS)
+        utool.__call__ = lambda: 'http://example.com/'
+
+        view = self._makeOne(context=context)
+
+        crumbs = view.breadcrumbs
+
+        self.assertEqual(len(crumbs), 3)
+        self.assertEqual(crumbs[0]['id'], 'root')
+        self.assertEqual(crumbs[0]['title'], 'SITE')
+        self.assertEqual(crumbs[0]['url'], 'http://example.com/')
+        self.assertEqual(crumbs[1]['id'], 'parent')
+        self.assertEqual(crumbs[1]['title'], 'PARENT')
+        self.assertEqual(crumbs[1]['url'], 'http://example.com/parent')
+        self.assertEqual(crumbs[2]['id'], 'child')
+        self.assertEqual(crumbs[2]['title'], 'CONTEXT')
+        self.assertEqual(crumbs[2]['url'], 'http://example.com/parent/child')
+
+    def test_member(self):
+        view = self._makeOne()
+        tool = view.context.portal_membership = DummyMembershipTool()
+        member = DummyUser()
+        tool.getAuthenticatedMember = lambda: member
+        self.failUnless(view.member is member)
+
+    def test_membersfolder(self):
+        view = self._makeOne()
+        tool = view.context.portal_membership = DummyMembershipTool()
+        membersfolder = object()
+        tool.getMembersFolder = lambda: membersfolder
+        self.failUnless(view.membersfolder is membersfolder)
+
+    def test_isAnon_tool_returns_True(self):
+        view = self._makeOne()
+        tool = view.context.portal_membership = DummyMembershipTool()
+        tool.isAnonymousUser = lambda: True
+        self.failUnless(view.isAnon)
+
+    def test_isAnon_tool_returns_False(self):
+        view = self._makeOne()
+        tool = view.context.portal_membership = DummyMembershipTool()
+        tool.isAnonymousUser = lambda: False
+        self.failIf(view.isAnon)
+
+    def test_uname_anonymous(self):
+        view = self._makeOne()
+        tool = view.context.portal_membership = DummyMembershipTool()
+        tool.isAnonymousUser = lambda: True
+        self.assertEqual(view.uname, 'Guest')
+
+    def test_uname_not_anonymous(self):
+        view = self._makeOne()
+        tool = view.context.portal_membership = DummyMembershipTool()
+        tool.isAnonymousUser = lambda: False
+        member = DummyUser()
+        member.getUserName = lambda: 'luser'
+        tool.getAuthenticatedMember = lambda: member
+        self.assertEqual(view.uname, 'luser')
+
+    def test_status_message_missing(self):
+        view = self._makeOne()
+        view.request.form = {}
+        self.assertEqual(view.status_message, None)
+
+    def test_status_message_missing(self):
+        view = self._makeOne()
+        view.request.form = {'portal_status_message': 'FOO'}
+        self.assertEqual(view.status_message, 'FOO')
+
+    def test_actions(self):
+        ACTIONS = {'global': [],
+                   'user': [],
+                   'object': [],
+                   'folder': [],
+                   'workflow': [],
+                  }
+        view = self._makeOne()
+        tool = view.context.portal_actions = DummyActionsTool(ACTIONS)
+        self.assertEqual(view.actions, ACTIONS)
+
+    def test_global_actions(self):
+        ACTIONS = {'global': [DummyAction('a'), DummyAction('b')],
+                   'user': [],
+                   'object': [],
+                   'folder': [],
+                   'workflow': [],
+                  }
+        view = self._makeOne()
+        tool = view.context.portal_actions = DummyActionsTool(ACTIONS)
+        self.assertEqual(view.global_actions, ACTIONS['global'])
+
+    def test_user_actions(self):
+        ACTIONS = {'global': [],
+                   'user': [DummyAction('a'), DummyAction('b')],
+                   'object': [],
+                   'folder': [],
+                   'workflow': [],
+                  }
+        view = self._makeOne()
+        tool = view.context.portal_actions = DummyActionsTool(ACTIONS)
+        self.assertEqual(view.user_actions, ACTIONS['user'])
+
+    def test_object_actions(self):
+        ACTIONS = {'global': [],
+                   'user': [],
+                   'object': [DummyAction('a'), DummyAction('b')],
+                   'folder': [],
+                   'workflow': [],
+                  }
+        view = self._makeOne()
+        tool = view.context.portal_actions = DummyActionsTool(ACTIONS)
+        self.assertEqual(view.object_actions, ACTIONS['object'])
+
+    def test_folder_actions(self):
+        ACTIONS = {'global': [],
+                   'user': [],
+                   'object': [],
+                   'folder': [DummyAction('a'), DummyAction('b')],
+                   'workflow': [],
+                  }
+        view = self._makeOne()
+        tool = view.context.portal_actions = DummyActionsTool(ACTIONS)
+        self.assertEqual(view.folder_actions, ACTIONS['folder'])
+
+    def test_workflow_actions(self):
+        ACTIONS = {'global': [],
+                   'user': [],
+                   'object': [],
+                   'folder': [],
+                   'workflow': [DummyAction('a'), DummyAction('b')],
+                  }
+        view = self._makeOne()
+        tool = view.context.portal_actions = DummyActionsTool(ACTIONS)
+        self.assertEqual(view.workflow_actions, ACTIONS['workflow'])
+
+class DummyContext:
+    pass
+
+class DummyAction:
+    def __init__(self, id):
+        self.id = id
+
+class DummySite:
+    def __init__(self, paths_to_contexts=()):
+        self.paths_to_contexts = paths_to_contexts[:]
+
+    def unrestrictedTraverse(self, path):
+        for known, context in self.paths_to_contexts:
+            if path == known:
+                return context
+        raise ValueError('Unknown path: %s' % path)
+
+class DummyPropertiesTool:
+    def getProperty(self, key, default):
+        return getattr(self, key, default)
+
+class DummyURLTool:
+    def __init__(self, site=None, paths_to_contexts=()):
+        self.site = site
+        self.paths_to_contexts = paths_to_contexts[:]
+
+    def getPortalObject(self):
+        return self.site
+
+    def getRelativeContentPath(self, context):
+        if context is self.site:
+            return ()
+        for path, known in self.paths_to_contexts:
+            if context is known:
+                return path
+        raise ValueError('Unknown context: %s' % context)
+
+class DummyMembershipTool:
+    pass
+
+class DummyActionsTool:
+    def __init__(self, actions=None):
+        if actions is None:
+            actions = {}
+        self.actions = actions.copy()
+
+    def listFilteredActionsFor(self, context):
+        return self.actions
+
+class DummyWorkflowTool:
+    review_state = 'DUMMY'
+    def getInfoFor(self, context, key, default):
+        if key == 'review_state':
+            return self.review_state
+
+class DummyUser:
+    pass
+
+class DummyResponse:
+    def __init__(self, **kw):
+        self._orig_headers = kw.copy()
+        self._set_headers = []
+
+    def getHeader(self, key):
+        return self._orig_headers.get(key, '')
+
+    def setHeader(self, key, value):
+        self._set_headers.append((key, value))
+
+class DummyRequest:
+    def __init__(self):
+        self.RESPONSE = DummyResponse()
+
+def test_suite():
+    return unittest.TestSuite((
+        unittest.makeSuite(UrsineGlobalsTests),
+    ))

Added: Products.CMFDefault/trunk/Products/CMFDefault/browser/ursa.py
===================================================================
--- Products.CMFDefault/trunk/Products/CMFDefault/browser/ursa.py	                        (rev 0)
+++ Products.CMFDefault/trunk/Products/CMFDefault/browser/ursa.py	2008-10-07 03:04:22 UTC (rev 91828)
@@ -0,0 +1,195 @@
+from Products.CMFDefault.utils import Message as _
+from Products.CMFDefault.utils import decode
+from Products.CMFDefault.browser.utils import ViewBase
+from Products.CMFDefault.browser.utils import memoize
+
+class UrsineGlobals(ViewBase):
+    """ Provide lazy / efficient template-level globals.
+
+    o Replaces 'getMainGlobals' in stock skin.
+    """
+    def __init__(self, context, request):
+        super(ViewBase, self).__init__(context, request)
+        ct = self.request.RESPONSE.getHeader('content-type') or ''
+        if not 'charset' in ct:
+            # Some newstyle views set a different charset - don't override it.
+            # Oldstyle views need the default_charset.
+            default_charset = self.ptool.getProperty('default_charset', None)
+            if default_charset:
+                self.request.RESPONSE.setHeader('content-type',
+                              '%s; charset=%s' % (ct, default_charset))
+
+    @property
+    @memoize
+    def ptool(self):
+        return self._getTool('portal_properties')
+
+    @property
+    @memoize
+    def utool(self):
+        return self._getTool('portal_url')
+
+    @property
+    @memoize
+    def mtool(self):
+        return self._getTool('portal_membership')
+
+    @property
+    @memoize
+    def atool(self):
+        return self._getTool('portal_actions')
+
+    @property
+    @memoize
+    def wtool(self):
+        return self._getTool('portal_workflow')
+
+    @property
+    @memoize
+    def portal_object(self):
+        return self.utool.getPortalObject()
+
+    @property
+    @memoize
+    def portal_url(self):
+        return self.utool()
+
+    @property
+    @memoize
+    def portal_title(self):
+        return self.portal_object.Title()
+
+    @property
+    @memoize
+    def object_title(self):
+        return self.context.Title()
+
+    @property
+    @memoize
+    def object_description(self):
+        return self.context.Description()
+
+    @property
+    @memoize
+    def trunc_id(self):
+        id = self.context.getId()
+        if len(id) > 15:
+            id = id[:15] + '...'
+        return id
+
+    @property
+    @memoize
+    def icon(self):
+        return getattr(self.context, 'getIcon',
+                        lambda: getattr(self.context, 'icon', ''))()
+    @property
+    @memoize
+    def typename(self):
+        return self.context.getPortalTypeName()
+
+    @property
+    @memoize
+    def wf_state(self):
+        return self.wtool.getInfoFor(self.context, 'review_state', '')
+
+    @property
+    @memoize
+    def page_title(self):
+        site_title = self.portal_title
+        page_title = self.object_title
+
+        if page_title != site_title:
+            page_title = site_title + ": " + page_title
+
+        return decode(page_title, self.context)
+
+    @property
+    @memoize
+    def breadcrumbs(self):
+        # XXX Shouldn't we just be walking up the aq_inner chain?
+        result = [{'id': _(u'root'),
+                   'title' : self.ptool.title(),
+                   'url' : self.portal_url,
+                  }]
+
+        relative = self.utool.getRelativeContentPath(self.context)
+        portal = self.portal_object
+
+        for i, token in enumerate(relative):
+            now = relative[:i+1]
+            obj = portal.unrestrictedTraverse(now)
+            if token != 'talkback':
+                result.append({'id': token,
+                               'title': obj.Title(),
+                               'url': obj.absolute_url(),
+                              })
+
+        return result
+
+    @property
+    @memoize
+    def member(self):
+        return self.mtool.getAuthenticatedMember()
+
+    @property
+    @memoize
+    def membername(self):
+        return self.isAnon and 'Guest' or self.member.getUserName()
+
+    @property
+    @memoize
+    def membersfolder(self):
+        return self.mtool.getMembersFolder()
+
+    @property
+    @memoize
+    def isAnon(self):
+        return self.mtool.isAnonymousUser()
+
+    @property
+    @memoize
+    def uname(self):
+        return self.isAnon and 'Guest' or self.member.getUserName()
+
+    @property
+    @memoize
+    def status_message(self):
+        message = self.request.form.get('portal_status_message')
+        if message is not None:
+            message = decode(message, self.context)
+        return message
+ 
+    @property
+    @memoize
+    def actions(self):
+        return self.atool.listFilteredActionsFor(self.context)
+    
+    @property
+    @memoize
+    def user_actions(self):
+        return self.actions['user']
+    
+    @property
+    @memoize
+    def object_actions(self):
+        return self.actions['object']
+    
+    @property
+    @memoize
+    def workflow_actions(self):
+        return self.actions['workflow']
+    
+    @property
+    @memoize
+    def folder_actions(self):
+        return self.actions['folder']
+    
+    @property
+    @memoize
+    def global_actions(self):
+        return self.actions['global']
+    
+    @property
+    @memoize
+    def add_actions(self):
+        return self.actions.get('folder/add', ())



More information about the Checkins mailing list