Use collective.z3cform.rolefield dependency, removed useless code

This commit is contained in:
Gauthier Bastien 2013-03-21 12:08:04 +01:00
parent c78c66186d
commit 36365a891a
12 changed files with 11 additions and 262 deletions

2
.gitignore vendored
View File

@ -7,6 +7,8 @@
.pydevproject
.settings/
bin/
include/
lib/
develop-eggs/
parts/
src/*

View File

@ -8,3 +8,4 @@ auto-checkout +=
plone.dexterity
z3c.form
plone.app.z3cform
collective.z3cform.rolefield

View File

@ -48,6 +48,7 @@ setup(name='collective.dms.basecontent',
'z3c.blobfile',
'plone.app.relationfield',
'plone.formwidget.contenttree',
'collective.z3cform.rolefield',
],
extras_require={
'test': ['plone.app.testing',

View File

@ -17,6 +17,7 @@ entrouvert_push = git+ssh://git@repos.entrouvert.org
[sources]
collective.dms.thesaurus = git ${remotes:collective}/collective.dms.thesaurus.git pushurl=${remotes:collective_push}/collective.dms.thesaurus.git
collective.dms.basecontent = git ${remotes:collective}/collective.dms.basecontent.git pushurl=${remotes:collective_push}/collective.dms.basecontent.git
collective.z3cform.rolefield = git ${remotes:collective}/collective.z3cform.rolefield.git pushurl=${remotes:collective_push}/collective.z3cform.rolefield.git
plone.app.z3cform = git ${remotes:plone}/plone.app.z3cform.git pushurl=${remotes:plone_push}/plone.app.z3cform.git
plone.dexterity = git ${remotes:cedricmessiant}/plone.dexterity.git pushurl=${remotes:cedricmessiant_push}/plone.dexterity.git
z3c.form = git ${remotes:zopefoundation}/z3c.form pushurl=${remotes:zopefoundation_push}/z3c.form

View File

@ -2,8 +2,6 @@ from zope.i18nmessageid import MessageFactory
_ = MessageFactory("collective.dms.basecontent")
from ._field import LocalRolesToPrincipals
def initialize(context):
"""Initializer called when used as a Zope 2 product."""

View File

@ -1,98 +0,0 @@
# -*- coding: utf-8 -*-
from zope.component import adapts
from zope.interface import implementer
from zope.interface import Interface
from zope.schema.interfaces import IList
from zope.schema import List, Tuple
from zope.interface import Invalid
from z3c.form.datamanager import AttributeField
import logging
logger = logging.getLogger('collective.dms.basecontent._field')
class ILocalRolesToPrincipals(IList):
"""Field that list principals depending on a vocabulary (by default list every available groups)
and that assign local roles defined in the roles_to_assign attribute."""
# this attribute will contains a tuple of principal to assign when the value is set
roles_to_assign = Tuple(
title=u"Roles to assign",
description=u"""\
Roles that will be automatically assigned as local roles to selected principals.
""",
required=True)
@implementer(ILocalRolesToPrincipals)
class LocalRolesToPrincipals(List):
"""Field that list principals depending on a vocabulary (by default list every available groups)
and that assign local roles defined in the roles_to_assign attribute."""
def __init__(self, roles_to_assign=(), **kw):
self.roles_to_assign = roles_to_assign
super(LocalRolesToPrincipals, self).__init__(**kw)
def validate(self, value):
"""Check that we have roles to assign, this is mendatory and
that roles we want to assign actually exist."""
super(LocalRolesToPrincipals, self)._validate(value)
# the field must specify some roles to assign as this is a required value
if not self.roles_to_assign:
raise Invalid(u'The field is not configured correctly, roles_to_assign is required. Contact system administrator!')
# check that roles we want to assign actually exist
existingRoles = [role for role in self.context.acl_users.portal_role_manager.listRoleIds()]
for role_to_assign in self.roles_to_assign:
if not role_to_assign in existingRoles:
raise Invalid(u'The field is not configured correctly, the defined role \'%s\' does not exist. Contact system administrator!' % role_to_assign)
class LocalRolesToPrincipalsDataManager(AttributeField):
"""A data manager which set local roles when saving the field."""
adapts(Interface, ILocalRolesToPrincipals)
def set(self, value):
"""See z3c.form.interfaces.IDataManager"""
# set local roles before setting the value so we still have access to the old value
roles_to_assign = self.field.roles_to_assign
# ---1 --- first find assigned roles to remove
# it is not that easy to remove local roles because no helper method exists for removing
# some specific local roles, only a method for removing every local roles for a list of principals...
old_value = self.field.get(self.context) or ()
# now check between old_value and value (new value) what is missing
removed_principals = set(old_value).difference(set(value))
# remove local_roles for removed_principals
for local_role in self.context.get_local_roles():
# a local_role is like ('Administrators', (u'Contributor', u'Reviewer'))
principal = local_role[0]
if principal in removed_principals:
cleaned_local_roles = list(local_role[1])
for role_to_assign in roles_to_assign:
try:
cleaned_local_roles.remove(role_to_assign)
except ValueError:
# if a role to remove was already removed (???) pass
logger.warn("Failed to remove role '%s' for principal '%s' on object '%s'" \
% (role_to_assign, principal, '/'.join(self.context.getPhysicalPath())))
# if there are still some local_roles, use manage_setLocalRoles
if cleaned_local_roles:
self.context.manage_setLocalRoles(principal, cleaned_local_roles)
else:
# either use manage_delLocalRoles
self.context.manage_delLocalRoles((principal,))
# ---2 --- now add new local roles
added_principals = set(value).difference(set(old_value))
for added_principal in added_principals:
self.context.manage_addLocalRoles(added_principal, roles_to_assign)
# finally set the value
super(LocalRolesToPrincipalsDataManager, self).set(value)
import plone.supermodel.exportimport
LocalRolesToPrincipalsHandler = plone.supermodel.exportimport.BaseHandler(LocalRolesToPrincipals)

View File

@ -36,13 +36,4 @@
name="schema_policy_dmsfile"
/>
<utility
component="._field.LocalRolesToPrincipalsHandler"
name="collective.dms.basecontent.LocalRolesToPrincipals"
/>
<adapter
factory="._field.LocalRolesToPrincipalsDataManager"
/>
</configure>

View File

@ -9,7 +9,7 @@ from five import grok
from collective.dms.basecontent.relateddocs import RelatedDocs
from . import _
from ._field import LocalRolesToPrincipals
from collective.z3cform.rolefield.field import LocalRolesToPrincipals
from zope.schema.interfaces import IVocabularyFactory
@ -20,27 +20,27 @@ class IDmsDocument(model.Schema):
notes = schema.Text(
title=_(u"Notes"),
required=False,
)
)
treating_groups = LocalRolesToPrincipals(
title=_(u"Treating groups"),
required=False,
roles_to_assign=('Editor',),
value_type=schema.Choice(vocabulary=u'collective.dms.basecontent.treating_groups',)
)
)
recipient_groups = LocalRolesToPrincipals(
title=_(u"Recipient groups"),
required=False,
roles_to_assign=('Reader',),
value_type=schema.Choice(vocabulary=u'collective.dms.basecontent.recipient_groups',)
)
)
related_docs = RelatedDocs(
title=_(u"Related documents"),
required=False,
display_backrefs=True)
display_backrefs=True,
)
class DmsDocument(Container):

View File

@ -1,8 +1,4 @@
<?xml version="1.0"?>
<metadata>
<version>0001</version>
<dependencies>
<dependency>profile-plone.app.dexterity:default</dependency>
<dependency>profile-plone.app.relationfield:default</dependency>
</dependencies>
</metadata>

View File

@ -1,5 +0,0 @@
<?xml version="1.0"?>
<object name="portal_types" meta_type="Plone Types Tool">
<property name="title">Controls the available content types in your portal</property>
<object name="testingtype" meta_type="Dexterity FTI"/>
</object>

View File

@ -1,55 +0,0 @@
<?xml version="1.0"?>
<object name="dmsdocument" meta_type="Dexterity FTI" i18n:domain="plone"
xmlns:i18n="http://xml.zope.org/namespaces/i18n">
<property name="title" i18n:translate="">TestingType</property>
<property name="description" i18n:translate="">None</property>
<property name="icon_expr">string:${portal_url}/folder_icon.png</property>
<property name="factory">testingtype</property>
<property name="add_view_expr">string:${folder_url}/++add++testingtype</property>
<property name="link_target"></property>
<property name="immediate_view">view</property>
<property name="global_allow">True</property>
<property name="filter_content_types">True</property>
<property name="allowed_content_types">
<element value="dmsmainfile"/>
<element value="dmsappendixfile"/>
</property>
<property name="allow_discussion">False</property>
<property name="default_view">view</property>
<property name="view_methods">
<element value="view"/>
</property>
<property name="default_view_fallback">False</property>
<property name="add_permission">cmf.AddPortalContent</property>
<property name="klass">plone.dexterity.content.Container</property>
<property name="behaviors">
<element value="plone.app.content.interfaces.INameFromTitle"/>
<element value="plone.app.dexterity.behaviors.metadata.IBasic"/>
</property>
<property name="schema" />
<property name="model_source">
&lt;model xmlns="http://namespaces.plone.org/supermodel/schema"&gt;
&lt;schema&gt;
&lt;field name="testingField" type="collective.dms.basecontent.LocalRolesToPrincipals"&gt;
&lt;title&gt;testingField&lt;/title&gt;
&lt;required&gt;False&lt;/required&gt;
&lt;roles_to_assign&gt;('Reader',)&lt;/roles_to_assign&gt;
&lt;/field&gt;
&lt;/schema&gt;
&lt;/model&gt;
</property>
<alias from="(Default)" to="(dynamic view)"/>
<alias from="edit" to="@@edit"/>
<alias from="sharing" to="@@sharing"/>
<alias from="view" to="(selected layout)"/>
<action title="View" action_id="view" category="object" condition_expr=""
description="" icon_expr="" link_target="" url_expr="string:${object_url}"
visible="True">
<permission value="View"/>
</action>
<action title="Edit" action_id="edit" category="object" condition_expr=""
description="" icon_expr="" link_target=""
url_expr="string:${object_url}/edit" visible="True">
<permission value="Modify portal content"/>
</action>
</object>

View File

@ -1,83 +0,0 @@
# -*- coding: utf8 -*-
import unittest2 as unittest
from zope.interface import Invalid
from plone.app.testing.helpers import setRoles
from ecreall.helpers.testing.base import BaseTest
from collective.dms.basecontent.testing import DMS_TESTS_PROFILE_FUNCTIONAL
from collective.dms.basecontent._field import LocalRolesToPrincipalsDataManager
class TestFields(unittest.TestCase, BaseTest):
"""Tests adapters"""
layer = DMS_TESTS_PROFILE_FUNCTIONAL
def setUp(self):
super(TestFields, self).setUp()
self.portal = self.layer['portal']
def _getTargetClass(self):
from collective.dms.basecontent._field import LocalRolesToPrincipals
return LocalRolesToPrincipals
def _makeOne(self, *args, **kw):
field = self._getTargetClass()(*args, **kw)
# this is needed to initialize the vocabulary
return field.bind(self.portal)
def test_roles_to_assign_attribute(self):
"""If the field is not correctly configured, it fails upon validation."""
field = self._makeOne()
# the roles_to_assign attribute is required, if empty, validate fails
self.assertEquals(field.roles_to_assign, ())
self.assertRaises(Invalid, field.validate, [])
# if we want to assign role but one does not exist, validate fails too
field = self._makeOne(roles_to_assign=('Editor', 'WrongRole',))
self.assertRaises(Invalid, field.validate, [])
# if we have valid values, it works like a charm ;-)
field = self._makeOne(roles_to_assign=('Editor', 'Reader',))
field.validate([])
def test_datamanager(self):
"""Test the local_roles assignment mechanism managed by the datamanager."""
testingfield = self.portal.portal_types.testingtype.lookupSchema()['testingField']
testingfield.roles_to_assign = ('Editor', 'Contributor',)
# first create a sample object
# make the default user a Manager
member = self.portal.portal_membership.getAuthenticatedMember()
setRoles(self.portal, member.getId(), ('Manager',))
# create an object
self.portal.invokeFactory('testingtype', id='testingobj')
testingobj = getattr(self.portal, 'testingobj')
datamanager = LocalRolesToPrincipalsDataManager(testingobj, testingfield)
self.failIf('Administrators' in testingobj.__ac_local_roles__.keys())
datamanager.set(('Administrators',))
# now we have local_roles for 'Administrators'
self.failUnless('Administrators' in testingobj.__ac_local_roles__.keys())
# moreover, local_roles for 'Administrators' are ('Editor', 'Contributor',)
self.assertEquals(tuple(testingobj.__ac_local_roles__['Administrators']), testingfield.roles_to_assign)
# add a principal, test that local_roles are adapted
self.failIf('Reviewers' in testingobj.__ac_local_roles__.keys())
# the value is now ('Administrators', 'Reviewers',)
datamanager.set(('Administrators', 'Reviewers',))
self.failUnless('Reviewers' in testingobj.__ac_local_roles__.keys())
self.assertEquals(tuple(testingobj.__ac_local_roles__['Reviewers']), testingfield.roles_to_assign)
# remove a group, check managed roles
# removing a group is made by passing new value where an existing group is no more present
self.failUnless('Administrators' in testingobj.__ac_local_roles__.keys())
datamanager.set(('Reviewers',))
self.failIf('Administrators' in testingobj.__ac_local_roles__.keys())
# if an external manipulation added a local_role not managed by the field, it is kept
# add a local_role for 'Reviewers' not managed by our field
self.assertEquals(tuple(testingobj.__ac_local_roles__['Reviewers']), testingfield.roles_to_assign)
testingobj.manage_addLocalRoles('Reviewers', ('Reader',))
self.assertEquals(tuple(testingobj.__ac_local_roles__['Reviewers']), testingfield.roles_to_assign + ('Reader',))
# remove the 'Reviewers' local_roles
datamanager.set(())
# not managed local_roles are kepts
self.assertEquals(tuple(testingobj.__ac_local_roles__['Reviewers']), ('Reader',))