Skip to content

Commit

Permalink
Merge 1ff5e07 into b6fa2ab
Browse files Browse the repository at this point in the history
  • Loading branch information
dataflake committed May 2, 2019
2 parents b6fa2ab + 1ff5e07 commit 4f67241
Show file tree
Hide file tree
Showing 12 changed files with 262 additions and 2 deletions.
3 changes: 3 additions & 0 deletions CHANGES.rst
Expand Up @@ -44,6 +44,9 @@ Fixes
Features
++++++++

- Resurrect the Interfaces ZMI tab
(`#450 <https://github.com/zopefoundation/Zope/issues/450>`_)

- Better default logging configuration for simple waitress WSGI setups
(`#526 <https://github.com/zopefoundation/Zope/issues/526>`_)

Expand Down
2 changes: 1 addition & 1 deletion setup.cfg
Expand Up @@ -49,7 +49,7 @@ omit =

[coverage:report]
precision = 2
show_missing = True
show_missing = False
sort = Name

[coverage:html]
Expand Down
2 changes: 2 additions & 0 deletions src/OFS/SimpleItem.py
Expand Up @@ -126,6 +126,8 @@ class Item(
isPrincipiaFolderish = 0
isTopLevelPrincipiaApplicationObject = 0

manage_options = ({'label': 'Interfaces', 'action': 'manage_interfaces'},)

def manage_afterAdd(self, item, container):
pass
manage_afterAdd.__five_method__ = True
Expand Down
1 change: 1 addition & 0 deletions src/Products/Five/utilities/browser/__init__.py
@@ -0,0 +1 @@
# package
20 changes: 20 additions & 0 deletions src/Products/Five/utilities/browser/configure.zcml
@@ -0,0 +1,20 @@
<configure xmlns="http://namespaces.zope.org/zope"
xmlns:browser="http://namespaces.zope.org/browser">

<browser:page
for="*"
name="edit-markers.html"
template="edit_markers.pt"
class="Products.Five.utilities.browser.marker.EditView"
permission="zope2.ManageProperties"
/>

<browser:page
for="*"
name="manage_interfaces"
template="manage_interfaces.pt"
class="Products.Five.utilities.browser.marker.EditView"
permission="zope2.ManageProperties"
/>

</configure>
82 changes: 82 additions & 0 deletions src/Products/Five/utilities/browser/edit_markers.pt
@@ -0,0 +1,82 @@
<html metal:use-macro="context/@@standard_macros/page">
<body>

<metal:slot metal:fill-slot="body">

<metal:macro metal:define-macro="heading">
<h1 i18n:translate="heading_edit_marker">Assign Marker Interfaces</h1>
</metal:macro>

<metal:macro metal:define-macro="main">
<p class="form-help formHelp" i18n:translate="">
Change the behavior of this object by adding or removing marker
interfaces. You can choose one or more interfaces to be added to the
list of provided interfaces for this object.
</p>

<p class="form-help formHelp" i18n:translate="">
A marker interface is used to identify an instance of a piece of
content. This allows you to enable and disable views based on marker
interfaces for example.
</p>

<form action="." method="post"
tal:attributes="action request/ACTUAL_URL">

<h3 i18n:translate="legend_provided">Provided interfaces</h3>

<table class="table table-striped table-hover table-sm">
<tr tal:repeat="interface view/getInterfaceNames">
<td class="zmi-object-check text-right">&nbsp;</td>
<td class="zmi-object-id"
tal:content="interface/name">Interface Name</td>
</tr>

<tr tal:repeat="interface view/getDirectlyProvidedNames">
<td class="zmi-object-check text-right">
<input type="checkbox" id="INTERFACE" name="remove:list"
tal:attributes="id interface/name;
value interface/name"/>
</td>
<td class="zmi-object-id"
tal:content="interface/name">Interface Name</td>
</tr>

<tr tal:condition="view/getDirectlyProvidedNames">
<td class="zmi-object-check text-right">&nbsp;</td>
<td class="zmi-controls">
<input class="btn btn-primary" type="submit" name="SAVE"
value="Remove" i18n:attributes="value"/>
</td>
</tr>
</table>

<h3 i18n:translate="legend_available_marker">
Available Marker Interfaces
</h3>

<table class="table table-striped table-hover table-sm">
<tr tal:repeat="interface view/getAvailableInterfaceNames">
<td class="zmi-object-check text-right">
<input type="checkbox" id="INTERFACE" name="add:list"
tal:attributes="id interface/name;
value interface/name"/>
</td>
<td class="zmi-object-id"
tal:content="interface/name">Interface Name</td>
</tr>
<tr tal:condition="view/getAvailableInterfaceNames">
<td class="zmi-object-check text-right">&nbsp;</td>
<td class="zmi-controls">
<input class="btn btn-primary" type="submit" name="SAVE"
value="Add" i18n:attributes="value"/>
</td>
</tr>
</table>

</form>
</metal:macro>
</metal:slot>

</body>
</html>
10 changes: 10 additions & 0 deletions src/Products/Five/utilities/browser/manage_interfaces.pt
@@ -0,0 +1,10 @@
<h1 tal:replace="structure context/manage_page_header">PAGE HEADER</h1>
<h2 tal:replace="structure context/manage_tabs">TABS</h2>

<main class="container-fluid">

<metal:macro metal:use-macro="context/@@edit-markers.html/main" />

</main>

<h1 tal:replace="structure context/manage_page_footer">PAGE FOOTER</h1>
55 changes: 55 additions & 0 deletions src/Products/Five/utilities/browser/marker.py
@@ -0,0 +1,55 @@
##############################################################################
#
# Copyright (c) 2004, 2005 Zope Foundation 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.
#
##############################################################################
"""Marker interfaces adapter views.
"""

from Products.Five.utilities.interfaces import IMarkerInterfaces


class EditView(object):
"""Marker interface edit view.
"""

def __init__(self, context, request):
self.context = context
self.request = request
self.adapted = IMarkerInterfaces(context)
self.context_url = self.context.absolute_url()

def __call__(self, SAVE=None, add=(), remove=()):
if SAVE:
self.update(add, remove)
url = '%s?manage_tabs_message=Changes+applied.'
self.request.response.redirect(url % self.request.ACTUAL_URL)
return ''
return self.index()

def _getNameLinkDicts(self, interfaceNames):
return [dict(name=name) for name in interfaceNames]

def getAvailableInterfaceNames(self):
return self._getNameLinkDicts(
self.adapted.getAvailableInterfaceNames())

def getDirectlyProvidedNames(self):
return self._getNameLinkDicts(self.adapted.getDirectlyProvidedNames())

def getInterfaceNames(self):
return self._getNameLinkDicts(self.adapted.getInterfaceNames())

def update(self, add, remove):
# this could return errors
add = self.adapted.dottedToInterfaces(add)
remove = self.adapted.dottedToInterfaces(remove)
self.adapted.update(add=add, remove=remove)
1 change: 1 addition & 0 deletions src/Products/Five/utilities/browser/tests/__init__.py
@@ -0,0 +1 @@
# package
82 changes: 82 additions & 0 deletions src/Products/Five/utilities/browser/tests/test_marker.py
@@ -0,0 +1,82 @@
##############################################################################
#
# Copyright (c) 2004, 2005 Zope Foundation 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.
#
##############################################################################
""" Tests for the marker interface edit views
"""
import AccessControl
import Products.Five
import Products.Five.utilities
from Products.Five.tests.testing.simplecontent import ISimpleContent
from Products.Five.tests.testing.simplecontent import SimpleContent
from Products.Five.utilities.browser.marker import EditView
from Testing.ZopeTestCase import ZopeTestCase
from Zope2.App import zcml
from zope.component import ComponentLookupError
from zope.component.interface import provideInterface
from zope.component.testing import setUp as component_setUp
from zope.component.testing import tearDown as component_tearDown


ISimpleContentName = 'Products.Five.tests.testing.simplecontent.ISimpleContent'
IFooMarkerName = 'Products.Five.utilities.browser.tests.test_marker.IFooMarker'


class IFooMarker(ISimpleContent):
pass


class MarkerViewTests(ZopeTestCase):

def setUp(self):
super(MarkerViewTests, self).setUp()
component_setUp()
zcml.load_config('meta.zcml', Products.Five)
zcml.load_config('permissions.zcml', AccessControl)
zcml.load_config('configure.zcml', Products.Five.utilities)

def tearDown(self):
super(MarkerViewTests, self).tearDown()
component_tearDown()

def test_editview(self):
obj = SimpleContent('foo', 'Foo').__of__(self.app.test_folder_1_)
view = EditView(obj, {})

# Test state before making any changes
self.assertTrue(view.context.aq_inner is obj)
self.assertEqual(view.request, {})
self.assertEqual(view.getAvailableInterfaceNames(), [])
self.assertEqual(view.getDirectlyProvidedNames(), [])
self.assertIn({'name': ISimpleContentName}, view.getInterfaceNames())

# Try to add a marker interface that doesn't exist
self.assertRaises(ComponentLookupError, view.update,
('__main__.IFooMarker',), ())

# Now create the marker interface and try again
provideInterface('', IFooMarker)
self.assertIn({'name': IFooMarkerName},
view.getAvailableInterfaceNames())
self.assertEqual(view.getDirectlyProvidedNames(), [])

# And try again to add it to the object
view.update((IFooMarkerName,), ())
self.assertEqual(view.getAvailableInterfaceNames(), [])
self.assertIn({'name': IFooMarkerName},
view.getDirectlyProvidedNames())

# And remove it again
view.update((), (IFooMarkerName,))
self.assertIn({'name': IFooMarkerName},
view.getAvailableInterfaceNames())
self.assertEqual(view.getDirectlyProvidedNames(), [])
2 changes: 2 additions & 0 deletions src/Products/Five/utilities/configure.zcml
@@ -1,5 +1,7 @@
<configure xmlns="http://namespaces.zope.org/zope">

<include package=".browser"/>

<adapter
for="*"
provides=".interfaces.IMarkerInterfaces"
Expand Down
4 changes: 3 additions & 1 deletion src/Shared/DC/Scripts/Bindings.py
Expand Up @@ -25,6 +25,7 @@
from Acquisition import aq_base
from Acquisition import aq_inner
from Acquisition import aq_parent
from zope.component import queryMultiAdapter as qma


defaultBindings = {'name_context': 'context',
Expand Down Expand Up @@ -246,7 +247,8 @@ def __before_publishing_traverse__(self, self2, request):
path = request['TraversalRequestNameStack']
names = self.getBindingAssignments()
if not names.isNameAssigned('name_subpath') or \
(path and hasattr(aq_base(self), path[-1])):
(path and hasattr(aq_base(self), path[-1])) or \
(path and qma((self, request), name=path[-1]) is not None):
return
subpath = path[:]
path[:] = []
Expand Down

0 comments on commit 4f67241

Please sign in to comment.