[Checkins] SVN: zmi.core/trunk/src/zmi/core/securitypolicy/ Copy zope.app.securitypolicy browser package to zmi.core.

Yusei Tahara yusei at domen.cx
Sat Aug 8 04:03:10 EDT 2009


Log message for revision 102569:
  Copy zope.app.securitypolicy browser package to zmi.core.
  

Changed:
  A   zmi.core/trunk/src/zmi/core/securitypolicy/
  A   zmi.core/trunk/src/zmi/core/securitypolicy/__init__.py
  A   zmi.core/trunk/src/zmi/core/securitypolicy/configure.zcml
  A   zmi.core/trunk/src/zmi/core/securitypolicy/granting.pt
  A   zmi.core/trunk/src/zmi/core/securitypolicy/granting.py
  A   zmi.core/trunk/src/zmi/core/securitypolicy/granting.txt
  A   zmi.core/trunk/src/zmi/core/securitypolicy/granting_ftest.txt
  A   zmi.core/trunk/src/zmi/core/securitypolicy/manage_access.pt
  A   zmi.core/trunk/src/zmi/core/securitypolicy/manage_permissionform.pt
  A   zmi.core/trunk/src/zmi/core/securitypolicy/manage_roleform.pt
  A   zmi.core/trunk/src/zmi/core/securitypolicy/rolepermissionview.py
  A   zmi.core/trunk/src/zmi/core/securitypolicy/tests/
  A   zmi.core/trunk/src/zmi/core/securitypolicy/tests/__init__.py
  A   zmi.core/trunk/src/zmi/core/securitypolicy/tests/functional.py
  A   zmi.core/trunk/src/zmi/core/securitypolicy/tests/functional.zcml
  A   zmi.core/trunk/src/zmi/core/securitypolicy/tests/rolepermissionmanager.py
  A   zmi.core/trunk/src/zmi/core/securitypolicy/tests/test_functional.py
  A   zmi.core/trunk/src/zmi/core/securitypolicy/tests/test_granting.py
  A   zmi.core/trunk/src/zmi/core/securitypolicy/tests/test_rolepermissionview.py

-=-
Added: zmi.core/trunk/src/zmi/core/securitypolicy/__init__.py
===================================================================
--- zmi.core/trunk/src/zmi/core/securitypolicy/__init__.py	                        (rev 0)
+++ zmi.core/trunk/src/zmi/core/securitypolicy/__init__.py	2009-08-08 08:03:09 UTC (rev 102569)
@@ -0,0 +1,17 @@
+##############################################################################
+#
+# Copyright (c) 2004 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.
+#
+##############################################################################
+"""Securitypolicy Views
+
+$Id: __init__.py 29365 2005-03-01 18:32:59Z sidnei $
+"""

Added: zmi.core/trunk/src/zmi/core/securitypolicy/configure.zcml
===================================================================
--- zmi.core/trunk/src/zmi/core/securitypolicy/configure.zcml	                        (rev 0)
+++ zmi.core/trunk/src/zmi/core/securitypolicy/configure.zcml	2009-08-08 08:03:09 UTC (rev 102569)
@@ -0,0 +1,96 @@
+<zope:configure
+    xmlns:zope="http://namespaces.zope.org/zope"
+    xmlns="http://namespaces.zope.org/browser"
+    i18n_domain="zope">
+
+<!-- RadioWidget for build a matrix for granting permissions -->
+  <zope:view
+      type="zope.publisher.interfaces.browser.IBrowserRequest"
+      for="zope.schema.interfaces.IChoice
+           zope.securitypolicy.interfaces.IGrantVocabulary"
+      provides="zope.app.form.interfaces.IInputWidget"
+      factory="zmi.core.browser.granting.GrantWidget"
+      permission="zope.Public"
+      />
+
+<!-- Role Utility -->
+
+  <addform
+      label="New Role"
+      name="addRole.html"
+      schema="zope.securitypolicy.interfaces.IRole"
+      permission="zope.Security"
+      content_factory="zope.securitypolicy.role.LocalRole"
+      arguments="title"
+      keyword_arguments="description"
+      fields="title description" />
+
+  <editform
+      schema="zope.securitypolicy.interfaces.IRole"
+      name="edit.html"
+      menu="zmi_views" title="Edit"
+      permission="zope.ManageContent"/>
+
+  <defaultView
+      for="zope.securitypolicy.interfaces.IRole"
+      name="edit.html" />
+
+  <!-- Menu entry for "Add Utility" menu -->
+  <addMenuItem
+      class="zope.securitypolicy.role.LocalRole"
+      title="Role"
+      description="A Security Role"
+      permission="zope.Security"
+      view="addRole.html"
+      />
+
+<!-- Role Permissions -->
+
+  <!-- Note that we've moved this to the site manager! -->
+  <!-- The role-permission mapping is really the domain of programmers -->
+
+  <pages
+      for="zope.app.component.interfaces.ILocalSiteManager"
+      permission="zope.Security"
+      class=".rolepermissionview.RolePermissionView">
+    <page
+        name="AllRolePermissions.html"
+        template="manage_access.pt"
+        menu="zmi_actions" title="Role-Permissions"
+        />
+    <!-- menu="zmi_actions" title="Role Permissions" / -->
+    <page
+        name="RolePermissions.html"
+        template="manage_roleform.pt"
+        />
+    <page
+        name="RolesWithPermission.html"
+        template="manage_permissionform.pt"
+        />
+  </pages>
+
+  <zope:class class=".rolepermissionview.PermissionRoles">
+    <zope:require
+        permission="zope.Security"
+        attributes="roles rolesInfo id title description" />
+  </zope:class>
+
+  <zope:class class=".rolepermissionview.RolePermissions">
+    <zope:require
+        permission="zope.Security"
+        attributes="permissions permissionsInfo id title description" />
+  </zope:class>
+
+<!-- Granting Roles and Permissions to Principals -->
+
+  <page
+      for="zope.annotation.interfaces.IAnnotatable"
+      name="grant.html"
+      permission="zope.Security"
+      template="granting.pt"
+      class=".granting.Granting"
+      menu="zmi_actions" title="Grant"
+      />
+
+
+</zope:configure>

Added: zmi.core/trunk/src/zmi/core/securitypolicy/granting.pt
===================================================================
--- zmi.core/trunk/src/zmi/core/securitypolicy/granting.pt	                        (rev 0)
+++ zmi.core/trunk/src/zmi/core/securitypolicy/granting.pt	2009-08-08 08:03:09 UTC (rev 102569)
@@ -0,0 +1,85 @@
+<html metal:use-macro="context/@@standard_macros/page"
+    i18n:domain="zope">
+<body>
+<div metal:fill-slot="body" i18n:domain="zope">
+  <h2 i18n:translate="">Granting Roles and Permissions to Principals</h2>
+  <p tal:define="status view/status"
+     tal:condition="status"
+     tal:content="status" i18n:translate=""/>
+  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+  <form action="" method="POST">
+
+    <div tal:content="structure view/principal_widget">...</div>
+
+    <div tal:condition="view/principal">
+
+      <h2 i18n:translate="">Grants for the selected principal</h2>
+      <input type="submit" name="GRANT_SUBMIT" value="Change" 
+             i18n:attributes="value grant-submit" />
+
+      <table width="100%" border="0">
+        <tr>
+          <td valign="top">
+            <table class="matrix">
+              <tr>
+                <td i18n:translate=""><strong>Roles</strong>&nbsp;</td>
+                <td i18n:translate=""><strong>Allow</strong>&nbsp;</td>
+                <td i18n:translate=""><strong>Unset</strong>&nbsp;</td>
+                <td i18n:translate=""><strong>Deny</strong>&nbsp;</td>
+              </tr>
+              <tr tal:repeat="widget view/roles">
+                <td valign="top" nowrap>
+                  <div class="label">
+                    <label for="field.name" title="The widget's hint"
+                           tal:attributes="for widget/name; title widget/hint"
+                           tal:content="widget/label"
+                           i18n:translate="">The Label</label>
+                  </div>
+                </td>
+                <tal:block tal:content="structure widget">
+                  roles widget
+                </tal:block>
+              </tr>
+              <tr>
+                <td colspan="2"><a href="#top" i18n:translate="">^ top</a></td>
+              </tr>
+            </table>
+          </td>
+          <td valign="top">
+            <table class="matrix">
+              <tr>
+                <td i18n:translate=""><strong>Permissions</strong>&nbsp;</td>
+                <td i18n:translate=""><strong>Allow</strong>&nbsp;</td>
+                <td i18n:translate=""><strong>Unset</strong>&nbsp;</td>
+                <td i18n:translate=""><strong>Deny</strong>&nbsp;</td>
+              </tr>
+              <tr tal:repeat="widget view/permissions">
+                <td valign="top" nowrap>
+                  <div class="label">
+                    <label for="field.name" title="The widget's hint"
+                           tal:attributes="for widget/name; title widget/hint"
+                           tal:content="widget/label"
+                           i18n:translate="">The Label</label>
+                  </div>
+                </td>
+                <tal:block tal:content="structure widget">
+                  permission widget
+                </tal:block>
+              </tr>
+              <tr>
+                <td colspan="2"><a href="#top" i18n:translate="">^ top</a></td>
+              </tr>
+            </table>
+          </td>
+        </tr>
+      </table>
+      <input type="submit" name="GRANT_SUBMIT" value="Change" 
+             i18n:attributes="value grant-submit" />
+
+    </div>
+  </form>
+</div>
+</body>
+</html>

Added: zmi.core/trunk/src/zmi/core/securitypolicy/granting.py
===================================================================
--- zmi.core/trunk/src/zmi/core/securitypolicy/granting.py	                        (rev 0)
+++ zmi.core/trunk/src/zmi/core/securitypolicy/granting.py	2009-08-08 08:03:09 UTC (rev 102569)
@@ -0,0 +1,241 @@
+##############################################################################
+#
+# Copyright (c) 2004 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.
+#
+##############################################################################
+"""Granting Roles and Permissions to Principals
+
+$Id: granting.py 85741 2008-04-26 07:46:02Z lgs $
+"""
+__docformat__ = "reStructuredText"
+
+import zope.schema
+from zope.component import getUtilitiesFor
+from zope.schema.vocabulary import SimpleTerm
+from zope.i18nmessageid import ZopeMessageFactory as _
+from zope.securitypolicy.interfaces import Allow, Unset, Deny
+from zope.securitypolicy.interfaces import IPrincipalPermissionManager
+from zope.securitypolicy.interfaces import IPrincipalRoleManager
+from zope.securitypolicy.interfaces import IRole
+from zope.securitypolicy.vocabulary import GrantVocabulary
+
+from zope.app.security.vocabulary import PrincipalSource
+from zope.app.form.utility import setUpWidget
+from zope.app.form.browser import RadioWidget
+from zope.app.form.browser.widget import renderElement
+from zope.app.form.interfaces import MissingInputError
+from zope.app.form.interfaces import IInputWidget
+from zope.app.security.interfaces import IPermission
+
+
+settings_vocabulary = GrantVocabulary(
+    [SimpleTerm(Allow, token="allow", title=_('Allow')),
+     SimpleTerm(Unset, token="unset", title=_('Unset')),
+     SimpleTerm(Deny,  token='deny',  title=_('Deny')),
+     ])
+
+
+class GrantWidget(RadioWidget):
+    """Grant widget for building a colorized matrix.
+
+    The matrix shows anytime the status if you edit the radio widgets.
+    This special widget shows the radio input field without labels.
+    The labels are added in the header of the table. The order of the radio
+    input fields is 'Allowed', 'Unset', 'Deny'.
+
+    """
+    orientation = "horizontal"
+    _tdTemplate = (
+        u'\n<td class="%s">\n<center>\n<label for="%s" title="%s">\n'
+        u'%s\n</label>\n</center>\n</td>\n'
+        )
+
+    def __call__(self):
+        """See IBrowserWidget."""
+        value = self._getFormValue()
+        contents = []
+        have_results = False
+
+        return self.renderValue(value)
+
+
+    def renderItem(self, index, text, value, name, cssClass):
+        """Render an item of the list. 
+
+        Revert the order of label and text. Added field id to the lable
+        attribute.
+
+        Added tabel td tags for fit in the matrix table.
+
+        """
+
+        tdClass = ''
+        id = '%s.%s' % (name, index)
+        elem = renderElement(u'input',
+                             value=value,
+                             name=name,
+                             id=id,
+                             cssClass=cssClass,
+                             type='radio',
+                             extra = 'onclick="changeMatrix(this);"')
+        return self._tdTemplate % (tdClass, id, text, elem)
+
+    def renderSelectedItem(self, index, text, value, name, cssClass):
+        """Render a selected item of the list. 
+
+        Revert the order of label and text. Added field id to the lable
+        attribute.
+        """
+
+        tdClass = 'default'
+        id = '%s.%s' % (name, index)
+        elem = renderElement(u'input',
+                             value=value,
+                             name=name,
+                             id=id,
+                             cssClass=cssClass,
+                             checked="checked",
+                             type='radio',
+                             extra = 'onclick="changeMatrix(this);"')
+        return self._tdTemplate % (tdClass, id, text, elem)
+
+    def renderItems(self, value):
+        # check if we want to select first item, the previously selected item
+        # or the "no value" item.
+        no_value = None
+        if (value == self.context.missing_value
+            and getattr(self, 'firstItem', False)
+            and len(self.vocabulary) > 0):
+            if self.context.required:
+                # Grab the first item from the iterator:
+                values = [iter(self.vocabulary).next().value]
+            else:
+                # the "no value" option will be checked
+                no_value = 'checked'
+        elif value != self.context.missing_value:
+            values = [value]
+        else:
+            values = []
+
+        items = self.renderItemsWithValues(values)
+        return items
+
+    def renderValue(self, value):
+        rendered_items = self.renderItems(value)
+        return " ".join(rendered_items)
+
+
+
+class Granting(object):
+
+    principal = None
+
+    principal_field = zope.schema.Choice(
+        __name__ = 'principal',
+        source=PrincipalSource(),
+        required=True)
+
+    def __init__(self, context, request):
+        self.context = context
+        self.request = request
+
+    def status(self):
+        setUpWidget(self, 'principal', self.principal_field, IInputWidget)
+        if not self.principal_widget.hasInput():
+            return u''
+        try:
+            principal = self.principal_widget.getInputValue()
+        except MissingInputError:
+            return u''
+
+        self.principal = principal
+
+        # Make sure we can use the principal id in a form by base64ing it
+        principal_token = unicode(principal).encode('base64').strip().replace(
+            '=', '_')
+
+        roles = [role for name, role in getUtilitiesFor(IRole)]
+        roles.sort(lambda x, y: cmp(x.title, y.title))
+        principal_roles = IPrincipalRoleManager(self.context)
+
+        self.roles = []
+        for role in roles:
+            name = principal_token + '.role.'+role.id
+            field = zope.schema.Choice(__name__= name,
+                                       title=role.title,
+                                       vocabulary=settings_vocabulary)
+            setUpWidget(self, name, field, IInputWidget,
+                        principal_roles.getSetting(role.id, principal))
+            self.roles.append(getattr(self, name+'_widget'))
+
+        perms = [perm for name, perm in getUtilitiesFor(IPermission)]
+        perms.sort(lambda x, y: cmp(x.title, y.title))
+        principal_perms = IPrincipalPermissionManager(self.context)
+
+        self.permissions = []
+        for perm in perms:
+            if perm.id == 'zope.Public':
+                continue
+            name = principal_token + '.permission.'+perm.id
+            field = zope.schema.Choice(__name__=name,
+                                       title=perm.title,
+                                       vocabulary=settings_vocabulary)
+            setUpWidget(self, name, field, IInputWidget,
+                        principal_perms.getSetting(perm.id, principal))
+            self.permissions.append(
+                getattr(self, name+'_widget'))
+
+        if 'GRANT_SUBMIT' not in self.request:
+            return u''
+
+        for role in roles:
+            name = principal_token + '.role.'+role.id
+            role_widget = getattr(self, name+'_widget')
+            if role_widget.hasInput():
+                try:
+                    setting = role_widget.getInputValue()
+                except MissingInputError:
+                    pass
+                else:
+                    # Arrgh!
+                    if setting is Allow:
+                        principal_roles.assignRoleToPrincipal(
+                            role.id, principal)
+                    elif setting is Deny:
+                        principal_roles.removeRoleFromPrincipal(
+                            role.id, principal)
+                    else:
+                        principal_roles.unsetRoleForPrincipal(
+                            role.id, principal)
+
+        for perm in perms:
+            if perm.id == 'zope.Public':
+                continue
+            name = principal_token + '.permission.'+perm.id
+            perm_widget = getattr(self, name+'_widget')
+            if perm_widget.hasInput():
+                try:
+                    setting = perm_widget.getInputValue()
+                except MissingInputError:
+                    pass
+                else:
+                    # Arrgh!
+                    if setting is Allow:
+                        principal_perms.grantPermissionToPrincipal(
+                            perm.id, principal)
+                    elif setting is Deny:
+                        principal_perms.denyPermissionToPrincipal(
+                            perm.id, principal)
+                    else:
+                        principal_perms.unsetPermissionForPrincipal(
+                            perm.id, principal)
+
+        return _('Grants updated.')

Added: zmi.core/trunk/src/zmi/core/securitypolicy/granting.txt
===================================================================
--- zmi.core/trunk/src/zmi/core/securitypolicy/granting.txt	                        (rev 0)
+++ zmi.core/trunk/src/zmi/core/securitypolicy/granting.txt	2009-08-08 08:03:09 UTC (rev 102569)
@@ -0,0 +1,203 @@
+Granting View
+=============
+
+The granting view allows the user to grant permissions and roles to
+principals. The view unfortunately depends on a lot of other components:
+
+  - Roles
+
+    >>> from zope.app.testing import ztapi
+    >>> from zope.securitypolicy.role import Role
+    >>> from zope.securitypolicy.interfaces import IRole
+    >>> ztapi.provideUtility(IRole, Role(u'role1', u'Role 1'), u'role1')
+    >>> ztapi.provideUtility(IRole, Role(u'role2', u'Role 2'), u'role2')
+    >>> ztapi.provideUtility(IRole, Role(u'role3', u'Role 3'), u'role3')
+
+  - Permissions
+
+    >>> from zope.security.permission import Permission
+    >>> from zope.security.interfaces import IPermission
+    >>> ztapi.provideUtility(IPermission, Permission(u'permission1',
+    ...                      u'Permission 1'), u'permission1')
+    >>> ztapi.provideUtility(IPermission, Permission(u'permission2',
+    ...                      u'Permission 2'), u'permission2')
+    >>> ztapi.provideUtility(IPermission, Permission(u'permission3',
+    ...                      u'Permission 3'), u'permission3')
+
+  - Authentication Utility
+
+    >>> class Principal:
+    ...     def __init__(self, id, title): self.id, self.title = id, title
+
+    >>> from zope.app.security.interfaces import IAuthentication
+    >>> from zope.app.security.interfaces import PrincipalLookupError
+    >>> from zope.interface import implements
+    >>> class AuthUtility:
+    ...     implements(IAuthentication)
+    ...     data = {'jim': Principal('jim', 'Jim Fulton'),
+    ...             'stephan': Principal('stephan', 'Stephan Richter')}
+    ...
+    ...     def getPrincipal(self, id):
+    ...         try:
+    ...             return self.data.get(id)
+    ...         except KeyError:
+    ...             raise PrincipalLookupError(id)
+    ...
+    ...     def getPrincipals(self, search):
+    ...         return [principal
+    ...                 for principal in self.data.values()
+    ...                 if search in principal.title]
+
+    >>> ztapi.provideUtility(IAuthentication, AuthUtility())
+
+  - Security-related Adapters
+
+    >>> from zope.annotation.interfaces import IAnnotatable
+    >>> from zope.securitypolicy.interfaces import IPrincipalRoleManager
+    >>> from zope.securitypolicy.principalrole import \
+    ...     AnnotationPrincipalRoleManager
+
+    >>> ztapi.provideAdapter(IAnnotatable, IPrincipalRoleManager,
+    ...                      AnnotationPrincipalRoleManager)
+
+    >>> from zope.securitypolicy.interfaces import \
+    ...     IPrincipalPermissionManager
+    >>> from zope.securitypolicy.principalpermission import \
+    ...     AnnotationPrincipalPermissionManager
+
+    >>> ztapi.provideAdapter(IAnnotatable, IPrincipalPermissionManager,
+    ...                      AnnotationPrincipalPermissionManager)
+
+  - Vocabulary Choice Widgets
+
+    >>> from zope.schema.interfaces import IChoice
+    >>> from zope.app.form.browser import ChoiceInputWidget
+    >>> from zope.app.form.interfaces import IInputWidget
+    >>> ztapi.browserViewProviding(IChoice, ChoiceInputWidget, IInputWidget)
+
+    >>> from zope.schema.interfaces import IVocabularyTokenized
+    >>> from zope.publisher.interfaces.browser import IBrowserRequest
+    >>> from zope.app.form.browser import DropdownWidget
+    >>> ztapi.provideMultiView((IChoice, IVocabularyTokenized),
+    ...                        IBrowserRequest, IInputWidget, '',
+    ...                        DropdownWidget)
+
+  - Support Views for the Principal Source Widget
+
+    >>> from zope.app.security.interfaces import IPrincipalSource
+    >>> from zope.app.security.browser.principalterms import PrincipalTerms
+    >>> from zope.browser.interfaces import ITerms
+    >>> ztapi.browserViewProviding(IPrincipalSource, PrincipalTerms, ITerms)
+
+    >>> from zope.app.security.browser.auth import AuthUtilitySearchView
+    >>> from zope.app.form.browser.interfaces import ISourceQueryView
+    >>> ztapi.browserViewProviding(IAuthentication,
+    ...                            AuthUtilitySearchView,
+    ...                            ISourceQueryView)
+
+
+    >>> from zope.schema.interfaces import ISource
+    >>> from zope.app.form.browser.source import SourceInputWidget
+    >>> ztapi.provideMultiView((IChoice, ISource), IBrowserRequest,
+    ...                        IInputWidget, '', SourceInputWidget)
+
+  - Attribute Annotatable Adapter
+
+    >>> from zope.app.testing import setup
+    >>> setup.setUpAnnotations()
+    >>> setup.setUpSiteManagerLookup()
+
+  - Content Object
+
+    >>> from zope.annotation.interfaces import IAttributeAnnotatable
+    >>> class Content:
+    ...     implements(IAttributeAnnotatable)
+    ...     __annotations__ = {}
+
+  (This is Jim's understanding of a "easy" setup!)
+
+Now that we have all the components we need, let's create *the* view.
+
+  >>> ob = Content()
+  >>> from zope.publisher.browser import TestRequest
+  >>> request = TestRequest()
+
+  >>> from zmi.core.securitypolicy.granting import Granting
+  >>> view = Granting(ob, request)
+
+If we call status, we get nothing and the view's principal attribute is `None`:
+
+  >>> view.status()
+  u''
+  >>> view.principal
+
+Since we have not selected a principal, we have no role or permission widgets:
+
+  >>> getattr(view, 'roles', None)
+  >>> getattr(view, 'permissions', None)
+
+Now that we have a selected principal, then
+
+
+  >>> view.request.form['field.principal.displayed'] = 'y'
+  >>> view.request.form['field.principal'] = 'amlt'
+
+(Yes, 'amlt' is the base 64 code for 'jim'.)
+
+  >>> view.status()
+  u''
+
+and now the `view.principal` is set:
+
+  >>> view.principal
+  'jim'
+
+Now we should have a list of role and permission widgets, and all of them
+should be unset, because do not have any settings for 'jim'.
+
+  >>> [role.context.title for role in view.roles]
+  [u'Role 1', u'Role 2', u'Role 3']
+  >>> [perm.context.title for perm in view.permissions]
+  [u'Permission 1', u'Permission 2', u'Permission 3']
+
+Now we change some settings and submit the form:
+
+  >>> from zope.securitypolicy.interfaces import Allow, Deny, Unset
+
+  >>> view.request.form['field.amlt.role.role1'] = 'unset'
+  >>> view.request.form['field.amlt.role.role1-empty-makrer'] = 1
+  >>> view.request.form['field.amlt.role.role2'] = 'allow'
+  >>> view.request.form['field.amlt.role.role2-empty-makrer'] = 1
+  >>> view.request.form['field.amlt.role.role3'] = 'deny'
+  >>> view.request.form['field.amlt.role.role3-empty-makrer'] = 1
+
+  >>> view.request.form['field.amlt.permission.permission1'] = 'unset'
+  >>> view.request.form['field.amlt.permission.permission1-empty-makrer'] = 1
+  >>> view.request.form['field.amlt.permission.permission2'] = 'allow'
+  >>> view.request.form['field.amlt.permission.permission2-empty-makrer'] = 1
+  >>> view.request.form['field.amlt.permission.permission3'] = 'deny'
+  >>> view.request.form['field.amlt.permission.permission3-empty-makrer'] = 1
+
+  >>> view.request.form['GRANT_SUBMIT'] = 'Submit'
+
+If we get the status now, the data should be written and a status message
+should be returned:
+
+  >>> view.status()
+  u'Grants updated.'
+
+  >>> roles = IPrincipalRoleManager(ob)
+  >>> roles.getSetting('role1', 'jim') is Unset
+  True
+  >>> roles.getSetting('role2', 'jim') is Allow
+  True
+  >>> roles.getSetting('role3', 'jim') is Deny
+  True
+
+  >>> roles = IPrincipalPermissionManager(ob)
+  >>> roles.getSetting('permission1', 'jim') is Unset
+  True
+  >>> roles.getSetting('permission2', 'jim') is Allow
+  True
+  >>> roles.getSetting('permission3', 'jim') is Deny
+  True


Property changes on: zmi.core/trunk/src/zmi/core/securitypolicy/granting.txt
___________________________________________________________________
Added: svn:eol-style
   + native

Added: zmi.core/trunk/src/zmi/core/securitypolicy/granting_ftest.txt
===================================================================
--- zmi.core/trunk/src/zmi/core/securitypolicy/granting_ftest.txt	                        (rev 0)
+++ zmi.core/trunk/src/zmi/core/securitypolicy/granting_ftest.txt	2009-08-08 08:03:09 UTC (rev 102569)
@@ -0,0 +1,195 @@
+Granting Example
+================
+
+In this example, we look at granting (or denying) principals (or
+roles) to principals.
+
+To make grants, we visit grant.html.  This doesn't display any
+grant information until we select a principal.
+
+  >>> print http(r"""
+  ... GET /@@grant.html HTTP/1.1
+  ... Authorization: Basic mgr:mgrpw
+  ... Referer: http://localhost:8081/@@contents.html
+  ... """)
+  HTTP/1.1 200 OK
+  ...
+
+If we submit a search request, we'll get a list of principals, from
+which we can choose:
+
+  >>> print http(r"""
+  ... POST /@@grant.html HTTP/1.1
+  ... Authorization: Basic mgr:mgrpw
+  ... Content-Length: 117
+  ... Content-Type: application/x-www-form-urlencoded
+  ... Referer: http://localhost:8081/@@grant.html
+  ...
+  ... field.principal.displayed=y"""
+  ... "&field.principal.MA__.searchstring="
+  ... "&field.principal.MA__.search=Search")
+  HTTP/1.1 200 OK
+  ...
+  <option value="em9wZS5tZ3I_">Manager</option>
+  ...
+
+We can then choose one.  If we do so, we get output that includes form
+elements for inputing security settings:
+
+  >>> print http(r"""
+  ... POST /@@grant.html HTTP/1.1
+  ... Authorization: Basic mgr:mgrpw
+  ... Content-Length: 62415
+  ... Content-Type: application/x-www-form-urlencoded
+  ... Referer: http://localhost:8081/@@grant.html
+  ...
+  ... field.principal.displayed=y"""
+  ... """&field.principal.MA__.searchstring="""
+  ... """&field.principal.MA__.selection=em9wZS5tZ3I_"""
+  ... """&field.principal.MA__.apply=Apply""")
+  HTTP/1.1 200 OK
+  ...
+  <td class="">
+  <center>
+  <label for="field.em9wZS5tZ3I_.role.zope.Member.0" title="Allow">
+  <input class="radioType" id="field.em9wZS5tZ3I_.role.zope.Member.0" name="field.em9wZS5tZ3I_.role.zope.Member" type="radio" value="allow" onclick="changeMatrix(this);" />
+  </label>
+  </center>
+  </td>
+  <BLANKLINE>
+  <td class="default">
+  <center>
+  <label for="field.em9wZS5tZ3I_.role.zope.Member.1" title="Unset">
+  <input class="radioType" checked="checked" id="field.em9wZS5tZ3I_.role.zope.Member.1" name="field.em9wZS5tZ3I_.role.zope.Member" type="radio" value="unset" onclick="changeMatrix(this);" />
+  </label>
+  </center>
+  </td>
+  <BLANKLINE>
+  <td class="">
+  <center>
+  <label for="field.em9wZS5tZ3I_.role.zope.Member.2" title="Deny">
+  <input class="radioType" id="field.em9wZS5tZ3I_.role.zope.Member.2" name="field.em9wZS5tZ3I_.role.zope.Member" type="radio" value="deny" onclick="changeMatrix(this);" />
+  </label>
+  </center>
+  </td>
+  ...
+  <td class="">
+  <center>
+  <label for="field.em9wZS5tZ3I_.permission.zope.ManageCode.0" title="Allow">
+  <input class="radioType" id="field.em9wZS5tZ3I_.permission.zope.ManageCode.0" name="field.em9wZS5tZ3I_.permission.zope.ManageCode" type="radio" value="allow" onclick="changeMatrix(this);" />
+  </label>
+  </center>
+  </td>
+  <BLANKLINE>
+  <td class="default">
+  <center>
+  <label for="field.em9wZS5tZ3I_.permission.zope.ManageCode.1" title="Unset">
+  <input class="radioType" checked="checked" id="field.em9wZS5tZ3I_.permission.zope.ManageCode.1" name="field.em9wZS5tZ3I_.permission.zope.ManageCode" type="radio" value="unset" onclick="changeMatrix(this);" />
+  </label>
+  </center>
+  </td>
+  <BLANKLINE>
+  <td class="">
+  <center>
+  <label for="field.em9wZS5tZ3I_.permission.zope.ManageCode.2" title="Deny">
+  <input class="radioType" id="field.em9wZS5tZ3I_.permission.zope.ManageCode.2" name="field.em9wZS5tZ3I_.permission.zope.ManageCode" type="radio" value="deny" onclick="changeMatrix(this);" />
+  </label>
+  </center>
+  ...
+
+Before we submit any data, there are no grants for the root object
+except for a one made by the testing framework that grants the manager
+role to the test manager:
+
+  >>> root = getRootFolder()
+  >>> import zope.securitypolicy.interfaces
+  >>> grants = zope.securitypolicy.interfaces.IGrantInfo(root)
+  >>> grants.principalPermissionGrant('zope.mgr', 'zope.ManageCode')
+  PermissionSetting: Unset
+  >>> list(grants.getRolesForPrincipal('zope.mgr'))
+  [('zope.Manager', PermissionSetting: Allow)]
+
+Now, we can submit changes. (I've actually reduced the form input
+to just the things we want to change to both limit the text here and
+to reduce dependencies on specific roles and permissions:
+
+
+  >>> print http(r"""
+  ... POST /@@grant.html HTTP/1.1
+  ... Authorization: Basic mgr:mgrpw
+  ... Content-Length: 62437
+  ... Content-Type: application/x-www-form-urlencoded
+  ... Referer: http://localhost:8081/@@grant.html
+  ...
+  ... field.principal=em9wZS5tZ3I_"""
+  ... """&field.principal.displayed=y"""
+  ... """&field.principal.MA__.searchstring="""
+  ... """&field.em9wZS5tZ3I_.role.zope.Member=allow"""
+  ... """&field.em9wZS5tZ3I_.role.zope.Member-empty-marker=1"""
+  ... """&field.em9wZS5tZ3I_.permission.zope.ManageCode=deny"""
+  ... """&field.em9wZS5tZ3I_.permission.zope.ManageCode-empty-marker=1"""
+  ... """&GRANT_SUBMIT=Change""")
+  HTTP/1.1 200 OK
+  ...
+  <td class="default">
+  <center>
+  <label for="field.em9wZS5tZ3I_.role.zope.Member.0" title="Allow">
+  <input class="radioType" checked="checked" id="field.em9wZS5tZ3I_.role.zope.Member.0" name="field.em9wZS5tZ3I_.role.zope.Member" type="radio" value="allow" onclick="changeMatrix(this);" />
+  </label>
+  </center>
+  </td>
+  <BLANKLINE>
+  <td class="">
+  <center>
+  <label for="field.em9wZS5tZ3I_.role.zope.Member.1" title="Unset">
+  <input class="radioType" id="field.em9wZS5tZ3I_.role.zope.Member.1" name="field.em9wZS5tZ3I_.role.zope.Member" type="radio" value="unset" onclick="changeMatrix(this);" />
+  </label>
+  </center>
+  </td>
+  <BLANKLINE>
+  <td class="">
+  <center>
+  <label for="field.em9wZS5tZ3I_.role.zope.Member.2" title="Deny">
+  <input class="radioType" id="field.em9wZS5tZ3I_.role.zope.Member.2" name="field.em9wZS5tZ3I_.role.zope.Member" type="radio" value="deny" onclick="changeMatrix(this);" />
+  </label>
+  </center>
+  </td>
+  ...
+  <td class="">
+  <center>
+  <label for="field.em9wZS5tZ3I_.permission.zope.ManageCode.0" title="Allow">
+  <input class="radioType" id="field.em9wZS5tZ3I_.permission.zope.ManageCode.0" name="field.em9wZS5tZ3I_.permission.zope.ManageCode" type="radio" value="allow" onclick="changeMatrix(this);" />
+  </label>
+  </center>
+  </td>
+  <BLANKLINE>
+  <td class="">
+  <center>
+  <label for="field.em9wZS5tZ3I_.permission.zope.ManageCode.1" title="Unset">
+  <input class="radioType" id="field.em9wZS5tZ3I_.permission.zope.ManageCode.1" name="field.em9wZS5tZ3I_.permission.zope.ManageCode" type="radio" value="unset" onclick="changeMatrix(this);" />
+  </label>
+  </center>
+  </td>
+  <BLANKLINE>
+  <td class="default">
+  <center>
+  <label for="field.em9wZS5tZ3I_.permission.zope.ManageCode.2" title="Deny">
+  <input class="radioType" checked="checked" id="field.em9wZS5tZ3I_.permission.zope.ManageCode.2" name="field.em9wZS5tZ3I_.permission.zope.ManageCode" type="radio" value="deny" onclick="changeMatrix(this);" />
+  </label>
+  </center>
+  ...
+
+And, if we check the grants, we see the changes:
+
+  >>> grants = zope.securitypolicy.interfaces.IGrantInfo(root)
+
+  >>> grants.principalPermissionGrant('zope.mgr', 'zope.ManageCode')
+  PermissionSetting: Deny
+
+  >>> role_grants = list(grants.getRolesForPrincipal('zope.mgr'))
+  >>> role_grants.sort()
+  >>> role_grants
+  ... # doctest: +NORMALIZE_WHITESPACE
+  [('zope.Manager', PermissionSetting: Allow),
+   ('zope.Member', PermissionSetting: Allow)]
+


Property changes on: zmi.core/trunk/src/zmi/core/securitypolicy/granting_ftest.txt
___________________________________________________________________
Added: svn:eol-style
   + native

Added: zmi.core/trunk/src/zmi/core/securitypolicy/manage_access.pt
===================================================================
--- zmi.core/trunk/src/zmi/core/securitypolicy/manage_access.pt	                        (rev 0)
+++ zmi.core/trunk/src/zmi/core/securitypolicy/manage_access.pt	2009-08-08 08:03:09 UTC (rev 102569)
@@ -0,0 +1,94 @@
+<html metal:use-macro="context/@@standard_macros/dialog" i18n:domain="zope">
+<head>
+  <tal:block
+      metal:fill-slot="headers"
+      tal:define="global pagetip view/pagetip"
+      />
+</head>
+<body>
+<div metal:fill-slot="body">
+
+   <p tal:define="status view/update"
+      tal:condition="status"
+      tal:content="status" i18n:translate=""/>
+
+  <form action="AllRolePermissions.html" method="POST">
+
+    <table width="100%" cellspacing="0" cellpadding="2" border="0"
+           nowrap="nowrap">
+
+      <tr class="list-header">
+        <td align="left" valign="top">
+          <div class="form-label">
+            <strong i18n:translate="">Permission</strong>
+          </div>
+        </td>
+        <td align="left">
+          <div class="form-label">
+            <strong i18n:translate="">Roles</strong>
+          </div>
+        </td>
+      </tr>
+
+      <tr class="row-normal">
+        <td></td>
+        <td align="center" tal:repeat="role view/roles">
+          <div class="list-item">
+            <a href="RolePermissions.html"
+              tal:attributes="
+              href string:RolePermissions.html?role_to_manage=${role/id}"
+              tal:content="role/title" i18n:translate="">Anonymous</a>
+            <input type="hidden" name="r0" value=""
+              tal:attributes="
+              name string:r${repeat/role/index};
+              value  string:${role/id}" />
+
+          </div>
+        </td>
+      </tr>
+
+      <tbody tal:repeat="perm view/permissionRoles">
+      <tr class="row-normal"
+          tal:attributes="class 
+             python:path('repeat/perm/even') and 'row-normal' or 'row-hilite'">
+        <td align="left" nowrap="nowrap">
+          <div class="list-item">
+             <a href="RolesWithPermission.html"
+                tal:attributes="href
+           string:RolesWithPermission.html?permission_to_manage=${perm/id}"
+                tal:content="perm/title"
+                i18n:translate="">Access Transient Objects</a>
+             <input type="hidden" name="r0" value=""
+                 tal:attributes="
+                 name string:p${repeat/perm/index};
+                 value  string:${perm/id}" />
+          </div>
+        </td>
+        <td align="center" tal:repeat="setting perm/roleSettings">
+          <select name="p0r0"
+              tal:attributes="name
+                  string:p${repeat/perm/index}r${repeat/setting/index}">
+            <option value="Unset"
+                tal:repeat="option view/availableSettings"
+                tal:attributes="value option/id;
+                                selected python:setting == option['id']"
+                tal:content="option/shorttitle">+</option>
+          </select>
+        </td>
+      </tr>
+      </tbody>
+
+      <tr>
+        <td colspan="5" align="left">
+          <div class="form-element">
+            <input class="form-element" type="submit" name="SUBMIT"
+                   value="Save Changes" i18n:attributes="value" />
+          </div>
+        </td>
+      </tr>
+    </table>
+  </form>
+
+</div>
+</body>
+</html>

Added: zmi.core/trunk/src/zmi/core/securitypolicy/manage_permissionform.pt
===================================================================
--- zmi.core/trunk/src/zmi/core/securitypolicy/manage_permissionform.pt	                        (rev 0)
+++ zmi.core/trunk/src/zmi/core/securitypolicy/manage_permissionform.pt	2009-08-08 08:03:09 UTC (rev 102569)
@@ -0,0 +1,96 @@
+<html metal:use-macro="context/@@standard_macros/page"
+    i18n:domain="zope">
+<head>
+  <style metal:fill-slot="headers" type="text/css">
+    <!--
+    .row-normal {
+      background-color: #ffffff;
+      border: none;
+    }
+
+    .row-hilite {
+      background-color: #efefef;
+      border: none;
+    }
+    -->
+  </style>
+</head>
+<body>
+<div metal:fill-slot="body">
+
+  <p tal:define="status view/update"
+     tal:condition="status"
+     tal:content="status" />
+
+  <p class="form-help" i18n:translate="">
+    Helpful message.
+  </p>
+
+  <div tal:define="perm 
+         python:view.permissionForID(request.get('permission_to_manage'))">
+
+    <p class="form-text" i18n:translate="">
+      Roles assigned to the permission
+      <strong tal:content="perm/title" 
+          i18n:name="perm_title" i18n:translate="">Change DTML Methods</strong>
+      (id: <strong tal:content="perm/id"
+          i18n:name="perm_id">Zope.Some.Permission</strong>)
+    </p>
+
+    <form action="AllRolePermissions.html" method="post">
+
+      <input type="hidden" name="permission_id" value="Permission Name"
+          tal:attributes="value perm/id" />
+
+        <div class="form-element">
+
+          <table width="100%" cellspacing="0" cellpadding="2" border="0" 
+              nowrap="nowrap">
+
+            <tr class="list-header">
+              <td align="left" valign="top">
+                <div class="form-label">
+                  <strong i18n:translate="">Role</strong>
+                </div>
+              </td>
+              <td align="left">
+                <div class="form-label">
+                  <strong i18n:translate="">Setting</strong>
+                </div>
+              </td>
+            </tr>
+
+            <tr class="row-normal"
+                tal:repeat="setting perm/roleSettings"
+                tal:attributes="class
+          python:path('repeat/setting/even') and 'row-normal' or 'row-hilite'">
+              <td align="left" valign="top"
+                  tal:define="ir repeat/setting/index"
+                  tal:content="python:path('view/roles')[ir].id">
+                Manager
+              </td>
+              <td>
+                <select name="settings:list">
+                    <option value="Unset"
+                       tal:repeat="option view/availableSettings"
+                       tal:attributes="value option/id;
+                                       selected python:setting == option['id']"
+                       tal:content="option/shorttitle"
+                       i18n:translate="">+</option>
+                </select>
+              </td>
+            </tr>
+        </table>
+
+      </div>
+
+      <div class="form-element">
+        <input class="form-element" type="submit" name="SUBMIT_PERMS" 
+            value="Save Changes" i18n:attributes="value save-changes-button"/>
+      </div>
+    </form>
+
+  </div>
+</div>
+</body>
+</html>

Added: zmi.core/trunk/src/zmi/core/securitypolicy/manage_roleform.pt
===================================================================
--- zmi.core/trunk/src/zmi/core/securitypolicy/manage_roleform.pt	                        (rev 0)
+++ zmi.core/trunk/src/zmi/core/securitypolicy/manage_roleform.pt	2009-08-08 08:03:09 UTC (rev 102569)
@@ -0,0 +1,76 @@
+<html metal:use-macro="context/@@standard_macros/page"
+    i18n:domain="zope">
+<body>
+<div metal:fill-slot="body">
+
+  <p tal:define="status view/update"
+     tal:condition="status"
+     tal:content="status" i18n:translate=""/>
+
+
+  <div tal:define="role 
+          python:view.roleForID(request.get('role_to_manage'))" tal:omit-tag="">
+
+    <p class="form-help" i18n:translate="">
+      This page shows the permissions allowed and denied the role
+        <strong tal:content="role/title"
+                i18n:name="role_title"
+                i18n:translate="">Great Master Guru</strong>
+        (id: <strong tal:content="role/id"
+                i18n:name="role_id">Zope.Some.Role</strong>).
+      To change settings, simply select different permissions in the
+      Allow or Deny lists. Make sure you don't select the same
+        permission in both lists though.
+    </p>
+
+
+    <form action="AllRolePermissions.html" method="POST">
+      <input type="hidden" name="role_id" value="Role ID"
+             tal:attributes="value role/id" />
+
+      <table width="100%" cellspacing="0" cellpadding="2" border="0" 
+             nowrap="nowrap"
+             tal:define="availableSettings 
+                python:view.availableSettings(noacquire=True)">
+
+        <tr class="list-header">
+          <td align="left" valign="top"
+              tal:repeat="setting availableSettings">
+            <div class="form-label">
+              <strong tal:content="setting/title"
+                    i18n:translate="">Allow</strong>
+            </div>
+          </td>
+        </tr>
+
+        <tr>
+          <td align="left" valign="top"
+              tal:repeat="settinginfo availableSettings">
+            <div class="form-element">
+              <select name="Unset:list" multiple="multiple" size="20"
+                      tal:define="setting settinginfo/id"
+                      tal:attributes="name string:${setting}:list">
+              <option tal:repeat="permissioninfo role/permissionsInfo"
+                      tal:content="permissioninfo/title"
+                      i18n:translate=""
+                      tal:attributes="selected
+                         python:path('permissioninfo/setting') == setting;
+                                      value permissioninfo/id"
+                      >Sample Permission</option>
+              </select>
+            </div>
+          </td>
+        </tr>
+      </table>
+
+      <div class="form-element">
+        <input class="form-element" type="submit" name="SUBMIT_ROLE" 
+            value="Save Changes" i18n:attributes="value save-changes-button"/>
+      </div>
+    </form>
+
+  </div>
+
+</div>
+</body>
+</html>

Added: zmi.core/trunk/src/zmi/core/securitypolicy/rolepermissionview.py
===================================================================
--- zmi.core/trunk/src/zmi/core/securitypolicy/rolepermissionview.py	                        (rev 0)
+++ zmi.core/trunk/src/zmi/core/securitypolicy/rolepermissionview.py	2009-08-08 08:03:09 UTC (rev 102569)
@@ -0,0 +1,240 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 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.
+#
+##############################################################################
+"""Role Permission View Classes
+
+$Id: rolepermissionview.py 85741 2008-04-26 07:46:02Z lgs $
+"""
+from datetime import datetime
+
+from zope.component import getUtilitiesFor, getUtility
+from zope.i18n import translate
+from zope.interface import implements
+from zope.exceptions.interfaces import UserError
+from zope.i18nmessageid import ZopeMessageFactory as _
+
+from zope.app.security.interfaces import IPermission
+from zope.securitypolicy.interfaces import Unset, Allow, Deny
+from zope.securitypolicy.interfaces import IRole, IRolePermissionManager
+
+class RolePermissionView(object):
+
+    _pagetip = _("""For each permission you want to grant (or deny) to a role,
+        set the entry for that permission and role to a '+' (or '-').
+        Permissions are shown on the left side, going down.
+        Roles are shown accross the top.
+        """)
+
+    def pagetip(self):
+        return translate(self._pagetip, context=self.request)
+
+    def roles(self):
+        roles = getattr(self, '_roles', None)
+        if roles is None:
+            roles = [
+                (translate(role.title, context=self.request).strip(), role)
+                for name, role in getUtilitiesFor(IRole)]
+            roles.sort()
+            roles = self._roles = [role for name, role in roles]
+        return roles
+
+    def permissions(self):
+        permissions = getattr(self, '_permissions', None)
+        if permissions is None:
+            permissions = [
+                (translate(perm.title, context=self.request).strip(), perm)
+                for name, perm in getUtilitiesFor(IPermission)
+                if name != 'zope.Public']
+            permissions.sort()
+            permissions = self._permissions = [perm
+                                               for name, perm in permissions]
+
+        return permissions
+
+    def availableSettings(self, noacquire=False):
+        aq = {'id': Unset.getName(), 'shorttitle': ' ',
+              'title': _('permission-acquire', 'Acquire')}
+        rest = [{'id': Allow.getName(), 'shorttitle': '+',
+                 'title': _('permission-allow', 'Allow')},
+                {'id': Deny.getName(), 'shorttitle': '-',
+                 'title': _('permission-deny', 'Deny')},
+                ]
+        if noacquire:
+            return rest
+        else:
+            return [aq]+rest
+
+    def permissionRoles(self):
+        context = self.context.__parent__
+        roles = self.roles()
+        return [PermissionRoles(permission, context, roles)
+                for permission in self.permissions()]
+
+    def permissionForID(self, pid):
+        roles = self.roles()
+        perm = getUtility(IPermission, pid)
+        return PermissionRoles(perm, self.context.__parent__, roles)
+
+    def roleForID(self, rid):
+        permissions = self.permissions()
+        role = getUtility(IRole, rid)
+        return RolePermissions(role, self.context.__parent__, permissions)
+
+
+    def update(self, testing=None):
+        status = ''
+        changed = False
+
+        if 'SUBMIT' in self.request:
+            roles       = [r.id for r in self.roles()]
+            permissions = [p.id for p in self.permissions()]
+            prm         = IRolePermissionManager(self.context.__parent__)
+            for ip in range(len(permissions)):
+                rperm = self.request.get("p%s" % ip)
+                if rperm not in permissions: continue
+                for ir in range(len(roles)):
+                    rrole = self.request.get("r%s" % ir)
+                    if rrole not in roles: continue
+                    setting = self.request.get("p%sr%s" % (ip, ir), None)
+                    if setting is not None:
+                        if setting == Unset.getName():
+                            prm.unsetPermissionFromRole(rperm, rrole)
+                        elif setting == Allow.getName():
+                            prm.grantPermissionToRole(rperm, rrole)
+                        elif setting == Deny.getName():
+                            prm.denyPermissionToRole(rperm, rrole)
+                        else:
+                            raise ValueError("Incorrect setting: %s" % setting)
+            changed = True
+
+        if 'SUBMIT_PERMS' in self.request:
+            prm = IRolePermissionManager(self.context.__parent__)
+            roles = self.roles()
+            rperm = self.request.get('permission_id')
+            settings = self.request.get('settings', ())
+            for ir in range(len(roles)):
+                rrole = roles[ir].id
+                setting = settings[ir]
+                if setting == Unset.getName():
+                    prm.unsetPermissionFromRole(rperm, rrole)
+                elif setting == Allow.getName():
+                    prm.grantPermissionToRole(rperm, rrole)
+                elif setting == Deny.getName():
+                    prm.denyPermissionToRole(rperm, rrole)
+                else:
+                    raise ValueError("Incorrect setting: %s" % setting)
+            changed = True
+
+        if 'SUBMIT_ROLE' in self.request:
+            role_id = self.request.get('role_id')
+            prm = IRolePermissionManager(self.context.__parent__)
+            allowed = self.request.get(Allow.getName(), ())
+            denied = self.request.get(Deny.getName(), ())
+            for permission in self.permissions():
+                rperm = permission.id
+                if rperm in allowed and rperm in denied:
+                    permission_translated = translate(
+                        permission.title, context=self.request)
+                    msg = _('You choose both allow and deny for permission'
+                            ' "${permission}". This is not allowed.',
+                            mapping = {'permission': permission_translated})
+                    raise UserError(msg)
+                if rperm in allowed:
+                    prm.grantPermissionToRole(rperm, role_id)
+                elif rperm in denied:
+                    prm.denyPermissionToRole(rperm, role_id)
+                else:
+                    prm.unsetPermissionFromRole(rperm, role_id)
+            changed = True
+
+        if changed:
+            formatter = self.request.locale.dates.getFormatter(
+                'dateTime', 'medium')
+            status = _("Settings changed at ${date_time}",
+                       mapping={'date_time':
+                                formatter.format(datetime.utcnow())})
+
+        return status
+
+
+class PermissionRoles(object):
+
+    implements(IPermission)
+
+    def __init__(self, permission, context, roles):
+        self._permission = permission
+        self._context    = context
+        self._roles      = roles
+
+    def _getId(self):
+        return self._permission.id
+
+    id = property(_getId)
+
+    def _getTitle(self):
+        return self._permission.title
+
+    title = property(_getTitle)
+
+    def _getDescription(self):
+        return self._permission.description
+
+    description = property(_getDescription)
+
+    def roleSettings(self):
+        """
+        Returns the list of setting names of each role for this permission.
+        """
+        prm = IRolePermissionManager(self._context)
+        proles = prm.getRolesForPermission(self._permission.id)
+        settings = {}
+        for role, setting in proles:
+            settings[role] = setting.getName()
+        nosetting = Unset.getName()
+        return [settings.get(role.id, nosetting) for role in self._roles]
+
+class RolePermissions(object):
+
+    implements(IRole)
+
+    def __init__(self, role, context, permissions):
+        self._role = role
+        self._context = context
+        self._permissions = permissions
+
+    def _getId(self):
+        return self._role.id
+
+    id = property(_getId)
+
+    def _getTitle(self):
+        return self._role.title
+
+    title = property(_getTitle)
+
+    def _getDescription(self):
+        return self._role.description
+
+    description = property(_getDescription)
+
+    def permissionsInfo(self):
+        prm = IRolePermissionManager(self._context)
+        rperms = prm.getPermissionsForRole(self._role.id)
+        settings = {}
+        for permission, setting in rperms:
+            settings[permission] = setting.getName()
+        nosetting = Unset.getName()
+        return [{'id': permission.id,
+                 'title': permission.title,
+                 'setting': settings.get(permission.id, nosetting)}
+                for permission in self._permissions]

Added: zmi.core/trunk/src/zmi/core/securitypolicy/tests/__init__.py
===================================================================
--- zmi.core/trunk/src/zmi/core/securitypolicy/tests/__init__.py	                        (rev 0)
+++ zmi.core/trunk/src/zmi/core/securitypolicy/tests/__init__.py	2009-08-08 08:03:09 UTC (rev 102569)
@@ -0,0 +1,2 @@
+#
+# This file is necessary to make this directory a package.

Added: zmi.core/trunk/src/zmi/core/securitypolicy/tests/functional.py
===================================================================
--- zmi.core/trunk/src/zmi/core/securitypolicy/tests/functional.py	                        (rev 0)
+++ zmi.core/trunk/src/zmi/core/securitypolicy/tests/functional.py	2009-08-08 08:03:09 UTC (rev 102569)
@@ -0,0 +1,38 @@
+##############################################################################
+#
+# Copyright (c) 2004 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.
+#
+##############################################################################
+"""Functional test case support
+
+$Id: functional.py 29143 2005-02-14 22:43:16Z srichter $
+"""
+
+from zope import interface
+from zope.app.testing import functional
+
+class ManagerSetup:
+    interface.implements(functional.IManagerSetup)
+
+    def setUpManager(self):
+        functional.HTTPCaller()(grant_request, handle_errors=False)
+
+grant_request = (r"""
+POST /@@grant.html HTTP/1.1
+Authorization: Basic Z2xvYmFsbWdyOmdsb2JhbG1ncnB3
+Content-Length: 5796
+Content-Type: application/x-www-form-urlencoded
+
+field.principal=em9wZS5tZ3I_"""
+"""&field.principal.displayed=y"""
+"""&GRANT_SUBMIT=Change"""
+"""&field.em9wZS5tZ3I_.role.zope.Manager=allow"""
+"""&field.em9wZS5tZ3I_.role.zope.Manager-empty-marker=1""")

Added: zmi.core/trunk/src/zmi/core/securitypolicy/tests/functional.zcml
===================================================================
--- zmi.core/trunk/src/zmi/core/securitypolicy/tests/functional.zcml	                        (rev 0)
+++ zmi.core/trunk/src/zmi/core/securitypolicy/tests/functional.zcml	2009-08-08 08:03:09 UTC (rev 102569)
@@ -0,0 +1,6 @@
+<configure
+    xmlns="http://namespaces.zope.org/zope">
+
+  <utility factory=".functional.ManagerSetup" />
+
+</configure>

Added: zmi.core/trunk/src/zmi/core/securitypolicy/tests/rolepermissionmanager.py
===================================================================
--- zmi.core/trunk/src/zmi/core/securitypolicy/tests/rolepermissionmanager.py	                        (rev 0)
+++ zmi.core/trunk/src/zmi/core/securitypolicy/tests/rolepermissionmanager.py	2009-08-08 08:03:09 UTC (rev 102569)
@@ -0,0 +1,87 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 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 IRolePermissionManager class that has no context.
+
+$Id: rolepermissionmanager.py 80149 2007-09-26 22:00:18Z rogerineichen $
+"""
+
+from zope.interface import implements
+from zope.securitypolicy.interfaces import Allow, Deny, Unset
+from zope.securitypolicy.interfaces import IRolePermissionManager
+from zope.securitypolicy.interfaces import IRolePermissionMap
+from zope.securitypolicy.securitymap import SecurityMap
+
+class RolePermissionManager(object):
+    """
+    provide adapter that manages role permission data in an object attribute
+    """
+
+    implements(IRolePermissionManager, IRolePermissionMap)
+
+    def __init__(self):
+        self._rp = SecurityMap()
+
+    def grantPermissionToRole(self, permission_id, role_id):
+        ''' See the interface IRolePermissionManager '''
+        rp = self._getRolePermissions(create=1)
+        rp.addCell(permission_id, role_id, Allow)
+
+    def denyPermissionToRole(self, permission_id, role_id):
+        ''' See the interface IRolePermissionManager '''
+        rp = self._getRolePermissions(create=1)
+        rp.addCell(permission_id, role_id, Deny)
+
+    def unsetPermissionFromRole(self, permission_id, role_id):
+        ''' See the interface IRolePermissionManager '''
+        rp = self._getRolePermissions()
+        # Only unset if there is a security map, otherwise, we're done
+        if rp:
+            rp.delCell(permission_id, role_id)
+
+    def getRolesForPermission(self, permission_id):
+        '''See interface IRolePermissionMap'''
+        rp = self._getRolePermissions()
+        if rp:
+            return rp.getRow(permission_id)
+        else:
+            return []
+
+    def getPermissionsForRole(self, role_id):
+        '''See interface IRolePermissionMap'''
+        rp = self._getRolePermissions()
+        if rp:
+            return rp.getCol(role_id)
+        else:
+            return []
+
+    def getRolesAndPermissions(self):
+        '''See interface IRolePermissionMap'''
+        rp = self._getRolePermissions()
+        if rp:
+            return rp.getAllCells()
+        else:
+            return []
+
+    def getSetting(self, permission_id, role_id):
+        '''See interface IRolePermissionMap'''
+        rp = self._getRolePermissions()
+        if rp:
+            return rp.queryCell(permission_id, role_id)
+        else:
+            return Unset
+
+    def _getRolePermissions(self, create=0):
+        """Get the role permission map stored in the context, optionally
+           creating one if necessary"""
+        return self._rp

Added: zmi.core/trunk/src/zmi/core/securitypolicy/tests/test_functional.py
===================================================================
--- zmi.core/trunk/src/zmi/core/securitypolicy/tests/test_functional.py	                        (rev 0)
+++ zmi.core/trunk/src/zmi/core/securitypolicy/tests/test_functional.py	2009-08-08 08:03:09 UTC (rev 102569)
@@ -0,0 +1,155 @@
+##############################################################################
+#
+# Copyright (c) 2003, 2004 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.
+#
+##############################################################################
+"""Functional tests for Security Policy's Grant screens.
+
+$Id: test_functional.py 81329 2007-10-31 19:53:46Z srichter $
+"""
+
+import re
+import unittest
+
+import zope.component
+from zope.testing import renormalizing
+from zope.security.interfaces import IPermission
+from zope.security.permission import Permission
+from zope.securitypolicy.role import Role
+from zope.securitypolicy.interfaces import IRole
+
+from zope.app.testing import functional
+from zope.app.securitypolicy.testing import SecurityPolicyLayer
+
+
+class RolePermissionsTest(functional.BrowserTestCase):
+
+    def testAllRolePermissionsForm(self):
+        response = self.publish(
+            '/++etc++site/@@AllRolePermissions.html',
+            basic='mgr:mgrpw')
+        self.assertEqual(response.getStatus(), 200)
+        body = response.getBody()
+        self.assert_('Permissions' in body)
+        self.assert_('Manage Content' in body)
+        self.assert_('Manage Site' in body)
+        self.assert_('Roles' in body)
+        self.assert_('Site Manager' in body)
+        self.assert_('Site Member' in body)
+        self.failIf(_result in body)
+        self.checkForBrokenLinks(body,
+                                 '/++etc++site/@@AllRolePermissions.html',
+                                 'mgr:mgrpw')
+
+    def testAllRolePermissions(self):
+        response = self.publish(
+            '/++etc++site/@@AllRolePermissions.html',
+            form={'p0r0': 'Allow',
+                  'p0': 'zope.ManageContent',
+                  'r0': 'zope.Manager',
+                  'SUBMIT': 'Save Changes'},
+            basic='mgr:mgrpw')
+        self.assertEqual(response.getStatus(), 200)
+        body = response.getBody()
+        self.assert_('<p>Settings changed' in body)
+        self.assert_(_result in body)
+
+    def testRolesWithPermissionsForm(self):
+        response = self.publish(
+            '/++etc++site/@@RolesWithPermissions.html'
+            '?permission_to_manage=zope.View',
+            basic='mgr:mgrpw')
+        self.assertEqual(response.getStatus(), 200)
+        body = response.getBody()
+        self.assert_('Roles assigned to the permission' in body)
+        self.assert_('Role' in body)
+        self.assert_('Setting' in body)
+        self.assert_('"Save Changes"' in body)
+        self.checkForBrokenLinks(body, '/@@RolesWithPermissions.html',
+                                 'mgr:mgrpw')
+
+    def testRolesWithPermissionsForm(self):
+        response = self.publish(
+            '/++etc++site/@@RolePermissions.html?role_to_manage=zope.Manager',
+            basic='mgr:mgrpw')
+        self.assertEqual(response.getStatus(), 200)
+        body = response.getBody()
+        self.assert_(
+            'This page shows the permissions allowed and denied the role'
+            in body)
+        self.assert_('Allow' in body)
+        self.assert_('Deny' in body)
+        self.checkForBrokenLinks(body, '/++etc++site/@@RolesPermissions.html',
+                                 'mgr:mgrpw')
+
+    def testAllRolePermissionsFormForLocalRoles(self):
+        role = Role(u"id", u"Local Role")
+        zope.component.provideUtility(role, IRole)
+        self.testAllRolePermissions()
+
+        response = self.publish(
+            '/++etc++site/@@AllRolePermissions.html',
+            basic='mgr:mgrpw')
+        body = response.getBody()
+        self.assert_('Local Role' in body)
+
+    def testAllRolePermissionsFormForLocalPermissions(self):
+        permission = Permission(u"id", u"Local Permission")
+        zope.component.provideUtility(permission, IPermission)
+        self.testAllRolePermissions()
+
+        response = self.publish(
+            '/++etc++site/@@AllRolePermissions.html',
+            basic='mgr:mgrpw')
+        body = response.getBody()
+        self.assert_('Local Permission' in body)
+
+    def testRolesWithPermissionsFormForLocalPermission(self):
+        permission = Permission(u"id", u"Local Permission")
+        zope.component.provideUtility(permission, IPermission, 'id')
+
+        response = self.publish(
+            '/++etc++site/@@AllRolePermissions.html',
+            form={'role_id': 'zope.Manager',
+                  'Allow': ['id'],
+                  'Deny': ['id'],
+                  'SUBMIT_ROLE': 'Save Changes'},
+            basic='mgr:mgrpw',
+            handle_errors=True)
+        body = response.getBody()
+        self.assert_('You choose both allow and deny for permission'
+            ' "Local Permission". This is not allowed.' in body)
+
+_result = '''\
+            <option value="Unset"> </option>
+            <option value="Allow" selected="selected">+</option>
+            <option value="Deny">-</option>
+'''
+
+
+checker = renormalizing.RENormalizing([
+    (re.compile(r"HTTP/1\.1 (\d\d\d) .*"), r"HTTP/1.1 \1 <MESSAGE>"),
+    ])
+
+
+def test_suite():
+    RolePermissionsTest.layer = SecurityPolicyLayer
+    granting = functional.FunctionalDocFileSuite(
+        '../granting_ftest.txt', checker=checker)
+    granting.layer = SecurityPolicyLayer
+    return unittest.TestSuite((
+        unittest.makeSuite(RolePermissionsTest),
+        granting,
+        ))
+
+
+if __name__ == '__main__':
+    unittest.main(defaultTest='test_suite')

Added: zmi.core/trunk/src/zmi/core/securitypolicy/tests/test_granting.py
===================================================================
--- zmi.core/trunk/src/zmi/core/securitypolicy/tests/test_granting.py	                        (rev 0)
+++ zmi.core/trunk/src/zmi/core/securitypolicy/tests/test_granting.py	2009-08-08 08:03:09 UTC (rev 102569)
@@ -0,0 +1,32 @@
+##############################################################################
+#
+# Copyright (c) 2004 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.
+#
+##############################################################################
+"""Security Policy Granting Views Tests
+
+$Id: test_granting.py 80149 2007-09-26 22:00:18Z rogerineichen $
+"""
+__docformat__ = "reStructuredText"
+import unittest
+from zope.testing import doctest
+from zope.app.testing import placelesssetup
+
+def test_suite():
+    return unittest.TestSuite((
+        doctest.DocFileSuite('../granting.txt',
+                             setUp=placelesssetup.setUp,
+                             tearDown=placelesssetup.tearDown),
+        ))
+
+if __name__ == '__main__':
+    unittest.main(defaultTest='test_suite')
+

Added: zmi.core/trunk/src/zmi/core/securitypolicy/tests/test_rolepermissionview.py
===================================================================
--- zmi.core/trunk/src/zmi/core/securitypolicy/tests/test_rolepermissionview.py	                        (rev 0)
+++ zmi.core/trunk/src/zmi/core/securitypolicy/tests/test_rolepermissionview.py	2009-08-08 08:03:09 UTC (rev 102569)
@@ -0,0 +1,220 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 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.
+#
+##############################################################################
+"""Role-Permission View Tests
+
+$Id: test_rolepermissionview.py 80149 2007-09-26 22:00:18Z rogerineichen $
+"""
+import unittest
+
+import zope.interface
+from zope.i18n.interfaces import ITranslationDomain
+from zope.i18nmessageid import Message
+from zope.publisher.browser import TestRequest, BrowserView
+from zope.exceptions.interfaces import UserError
+from zope.security.permission import Permission
+from zope.security.interfaces import IPermission
+
+from zope.app.testing import ztapi
+from zope.app.component.testing import PlacefulSetup
+
+from zope.securitypolicy.role import Role
+from zope.securitypolicy.interfaces import IRole
+
+from zmi.core.securitypolicy.tests.rolepermissionmanager import \
+     RolePermissionManager
+from zmi.core.securitypolicy.rolepermissionview import RolePermissionView
+
+class RolePermissionView(RolePermissionView, BrowserView):
+    """Adding BrowserView to Utilities; this is usually done by ZCML."""
+
+class TranslationDomain:
+    zope.interface.implements(ITranslationDomain)
+
+    def __init__(self, **translations):
+        self.translations = translations
+
+    def translate(self, msgid, *ignored, **also_ignored):
+        return self.translations.get(msgid, msgid)
+
+
+def defineRole(id, title=None, description=None):
+    role = Role(id, title, description)
+    ztapi.provideUtility(IRole, role, name=role.id)
+    return role
+
+def definePermission(id, title=None, description=None):
+    permission = Permission(id, title, description)
+    ztapi.provideUtility(IPermission, permission, name=permission.id)
+    return permission
+
+class FakeSiteManager:
+
+    def __init__(self, site):
+        self.__parent__ = site
+
+class Test(PlacefulSetup, unittest.TestCase):
+
+    def setUp(self):
+        PlacefulSetup.setUp(self)
+        defineRole('manager', Message('Manager', 'testdomain'))
+        defineRole('member',  Message('Member', 'testdomain'))
+        definePermission('read', Message('Read', 'testdomain'))
+        definePermission('write', Message('Write', 'testdomain'))
+        site = RolePermissionManager()
+        self.view = RolePermissionView(FakeSiteManager(site), None)
+        ztapi.provideUtility(ITranslationDomain,
+                             TranslationDomain(Member="A Member",
+                                               Write="A Write",
+                                               ),
+                             'testdomain')
+
+    def testRoles(self):
+        self.assertEqual([role.title for role in self.view.roles()],
+                         ["Member", "Manager"])
+
+    def testPermisssions(self):
+        self.assertEqual([role.title for role in self.view.permissions()],
+                         ["Write", "Read"])
+
+    def testMatrix(self):
+        roles = self.view.roles()
+        permissions = self.view.permissions()
+
+        #         manager  member
+        # read       +
+        # write      .       -
+        env = {
+            'p0': 'read', 'p1': 'write',
+            'r0': 'manager', 'r1': 'member',
+            'p0r0': 'Allow',
+            'p1r0': 'Unset', 'p1r1': 'Deny',
+            'SUBMIT': 1
+            }
+        self.view.request = TestRequest(environ=env)
+        self.view.update()
+        permissionRoles = self.view.permissionRoles()
+        for ip in range(len(permissionRoles)):
+            permissionRole = permissionRoles[ip]
+            rset = permissionRole.roleSettings()
+            for ir in range(len(rset)):
+                setting = rset[ir]
+                r = roles[ir].id
+                p = permissions[ip].id
+                if setting == 'Allow':
+                    self.failUnless(r == 'manager' and p == 'read')
+                elif setting == 'Deny':
+                    self.failUnless(r == 'member' and p == 'write')
+                else:
+                    self.failUnless(setting == 'Unset')
+
+        #         manager  member
+        # read       -
+        # write      +
+        env = {
+            'p0': 'read', 'p1': 'write',
+            'r0': 'manager', 'r1': 'member',
+            'p0r0': 'Deny',
+            'p1r0': 'Allow', 'p1r1': 'Unset',
+            'SUBMIT': 1
+            }
+        self.view.request = TestRequest(environ=env)
+        self.view.update()
+        permissionRoles = self.view.permissionRoles()
+        for ip in range(len(permissionRoles)):
+            permissionRole = permissionRoles[ip]
+            rset = permissionRole.roleSettings()
+            for ir in range(len(rset)):
+                setting = rset[ir]
+                r = roles[ir].id
+                p = permissions[ip].id
+                if setting == 'Allow':
+                    self.failUnless(r == 'manager' and p == 'write')
+                elif setting == 'Deny':
+                    self.failUnless(r == 'manager' and p == 'read')
+                else:
+                    self.failUnless(setting == 'Unset')
+
+    def testPermissionRoles(self):
+        env={'permission_id': 'write',
+             'settings': ['Allow', 'Unset'],
+             'SUBMIT_PERMS': 1}
+        self.view.request = TestRequest(environ=env)
+        self.view.update()
+        permission = self.view.permissionForID('write')
+        settings = permission.roleSettings()
+        self.assertEquals(settings, ['Allow', 'Unset'])
+
+
+        env={'permission_id': 'write',
+             'settings': ['Unset', 'Deny'],
+             'SUBMIT_PERMS': 1}
+        self.view.request = TestRequest(environ=env)
+        self.view.update()
+        permission = self.view.permissionForID('write')
+        settings = permission.roleSettings()
+        self.assertEquals(settings, ['Unset', 'Deny'])
+
+        env={'permission_id': 'write',
+             'settings': ['Unset', 'foo'],
+             'SUBMIT_PERMS': 1}
+        self.view.request = TestRequest(environ=env)
+        self.assertRaises(ValueError, self.view.update)
+
+    def testRolePermissions(self):
+        env={'Allow': ['read'],
+             'Deny': ['write'],
+             'SUBMIT_ROLE': 1,
+             'role_id': 'member'}
+        self.view.request = TestRequest(environ=env)
+        self.view.update(1)
+        role = self.view.roleForID('member')
+        pinfos = role.permissionsInfo()
+        for pinfo in pinfos:
+            pid = pinfo['id']
+            if pid == 'read':
+                self.assertEquals(pinfo['setting'], 'Allow')
+            if pid == 'write':
+                self.assertEquals(pinfo['setting'], 'Deny')
+
+        env={'Allow': [],
+             'Deny': ['read'],
+             'SUBMIT_ROLE': 1,
+             'role_id': 'member'}
+        self.view.request = TestRequest(environ=env)
+        self.view.update()
+        role = self.view.roleForID('member')
+        pinfos = role.permissionsInfo()
+        for pinfo in pinfos:
+            pid = pinfo['id']
+            if pid == 'read':
+                self.assertEquals(pinfo['setting'], 'Deny')
+            if pid == 'write':
+                self.assertEquals(pinfo['setting'], 'Unset')
+
+
+    def testRolePermissions_UserError(self):
+        env={'Allow': ['read'],
+             'Deny': ['read'],
+             'SUBMIT_ROLE': 1,
+             'role_id': 'member'}
+        self.view.request = TestRequest(environ=env)
+        self.assertRaises(UserError, self.view.update, 1)
+
+
+def test_suite():
+    loader=unittest.TestLoader()
+    return loader.loadTestsFromTestCase(Test)
+
+if __name__=='__main__':
+    unittest.TextTestRunner().run(test_suite())



More information about the Checkins mailing list