Commit 6b2ca4f0 authored by Arnaud Fontaine's avatar Arnaud Fontaine

Add Content Existence Constraint for ZODB Property Sheets and its

corresponding test


git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@40750 20353a03-c40f-0410-a6d1-a30d3c3de9de
parent 858cca56
......@@ -38,13 +38,17 @@ from Products.ERP5Type.Utils import createExpressionContext
class AttributeEqualityConstraint(ConstraintMixin):
"""
This constraint checks the values of a given attribute name on this
object. This is only relevant for ZODB Property Sheets (filesystem
Property Sheets rely on Products.ERP5Type.Constraint.PropertyExistence
instead). Note that the attribute expected value is now a TALES
Expression to be able to use any Python type and not only strings.
object.
This is only relevant for ZODB Property Sheets (filesystem Property
Sheets rely on Products.ERP5Type.Constraint.AttributeEquality
instead).
Note that the attribute expected value is now a TALES Expression to
be able to use any Python type and not only strings.
For example, if we would like to check whether the attribute 'title'
has 'ObjectTitle' as its value, we would create a 'Attribute
has 'ObjectTitle' as its value, we would create an 'Attribute
Equality Constraint' within that Property Sheet and set 'title' as
the 'Attribute Name' and 'python: "ObjectTitle"' as the 'Attribute
Value', then set the 'Predicate' if necessary (known as 'condition'
......@@ -121,7 +125,7 @@ class AttributeEqualityConstraint(ConstraintMixin):
error = self._generateError(
obj, self._getMessage(message_id),
dict(attribute_name=attribute_name,
attribute_value=attribute_value,
current_value=attribute_value,
expected_value=attribute_expected_value))
return [error]
......
......@@ -35,9 +35,11 @@ from Products.ERP5Type import Permissions, PropertySheet
class CategoryExistenceConstraint(ConstraintMixin):
"""
This constraint checks whether a category has been defined on this
object (without acquisition). This is only relevant for ZODB
Property Sheets (filesystem Property Sheets rely on
Products.ERP5Type.Constraint.CategoryExistence instead).
object (without acquisition).
This is only relevant for ZODB Property Sheets (filesystem Property
Sheets rely on Products.ERP5Type.Constraint.CategoryExistence
instead).
"""
meta_type = 'ERP5 Category Existence Constraint'
portal_type = 'Category Existence Constraint'
......
##############################################################################
#
# Copyright (c) 2006 Nexedi SARL and Contributors. All Rights Reserved.
# Romain Courteaud <romain@nexedi.com>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
from Products.ERP5Type.mixin.constraint import ConstraintMixin
from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions, PropertySheet
from Products.CMFCore.Expression import Expression
from Products.ERP5Type.Utils import createExpressionContext
class ContentExistenceConstraint(ConstraintMixin):
"""
This constraint checks whether the given object contains at least
one subobject. It also allows to filter the subobjects by their
Portal Types.
This is only relevant for ZODB Property Sheets (filesystem Property
Sheets rely on Products.ERP5Type.Constraint.ContentExistence
instead).
Note that the portal_type is now a TALES Expression, meaningful to
be able to call a method returning a list of Portal Types.
For example, if we would like to check whether the object contains
subobjects whose Portal Types could be ("Foo", "Bar"), then we would
create a 'Content Existence Constraint' within that Property Sheet
and set 'Portal Types' to ("Foo", "Bar"), then set the 'Predicate'
if necessary (known as 'condition' for filesystem Property Sheets).
"""
meta_type = 'ERP5 Content Existence Constraint'
portal_type = 'Content Existence Constraint'
# Declarative security
security = ClassSecurityInfo()
security.declareObjectProtected(Permissions.AccessContentsInformation)
property_sheets = (PropertySheet.SimpleItem,
PropertySheet.Predicate,
PropertySheet.Reference,
PropertySheet.ContentExistenceConstraint)
# Define by default error messages
_message_id_list = [ 'message_no_subobject',
'message_no_subobject_portal_type' ]
message_no_subobject = "The document does not contain any subobject"
message_no_subobject_portal_type = "The document does not contain any"\
" subobject of portal portal type ${portal_type}"
def checkConsistency(self, obj, fixit=0):
"""
Checks that object contains at least one subobject and, if a list
of Portal Type has been given, check their Portal Types
"""
if not self.test(obj):
return []
portal_type = Expression(self.getConstraintPortalType())(
createExpressionContext(obj))
# If there is at least one subobject with the given Portal Type,
# then return now
if len(obj.contentValues(portal_type=portal_type)) > 0:
return []
# Otherwise, generate an error message
mapping = {}
if portal_type is ():
message_id = 'message_no_subobject'
else:
message_id = 'message_no_subobject_portal_type'
from Products.ERP5Type.Message import Message
mapping['portal_type'] = str(Message('erp5_ui', ' or ')).join(
[str(Message('erp5_ui', pt)) for pt in portal_type])
return [self._generateError(obj,
self._getMessage(message_id),
mapping)]
......@@ -35,8 +35,10 @@ from Products.ERP5Type import Permissions, PropertySheet
class PropertyExistenceConstraint(ConstraintMixin):
"""
This constraint checks whether a property has been defined on this
object. This is only relevant for ZODB Property Sheets (filesystem
Property Sheets rely on Products.ERP5Type.Constraint.PropertyExistence
object.
This is only relevant for ZODB Property Sheets (filesystem Property
Sheets rely on Products.ERP5Type.Constraint.PropertyExistence
instead).
For example, if we would like to check whether an invoice line has a
......
......@@ -34,6 +34,7 @@ class AttributeEqualityConstraint:
{ 'id': 'constraint_attribute_name',
'type': 'string',
'description' : 'Attribute name whose values are checked' },
# TALES Expression
{ 'id': 'constraint_attribute_value',
'type': 'string',
'description' : 'Valid values of the Attribute' },
......
##############################################################################
#
# Copyright (c) 2010 Nexedi SARL and Contributors. All Rights Reserved.
# Arnaud Fontaine <arnaud.fontaine@nexedi.com>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
class ContentExistenceConstraint:
"""
Define a Content Existence Constraint for ZODB Property Sheets
"""
_properties = (
# TALES Expression
{ 'id': 'constraint_portal_type',
'type': 'string',
'description' : 'Portal type',
'default': 'python: ()' },
{ 'id': 'message_no_subobject',
'type': 'string',
'description' : 'Error message when there is no subobject' },
{ 'id': 'message_no_subobject_portal_type',
'type': 'string',
'description' : 'Error message when there is no subobject of the given portal type' },
)
......@@ -20,3 +20,4 @@ from DynamicCategoryProperty import DynamicCategoryProperty
from CategoryExistenceConstraint import CategoryExistenceConstraint
from PropertyExistenceConstraint import PropertyExistenceConstraint
from AttributeEqualityConstraint import AttributeEqualityConstraint
from ContentExistenceConstraint import ContentExistenceConstraint
......@@ -365,6 +365,12 @@ class TestZodbPropertySheet(ERP5TypeTestCase):
constraint_attribute_name='categories_list',
constraint_attribute_value='python: ("sub_category1", "sub_category2")')
def _newContentExistenceConstraint(self):
self.test_property_sheet.newContent(
reference='test_content_existence_constraint',
portal_type='Content Existence Constraint',
constraint_portal_type='python: ("Folder")')
def afterSetUp(self):
"""
Create a test Property Sheet (and its properties)
......@@ -395,6 +401,10 @@ class TestZodbPropertySheet(ERP5TypeTestCase):
# Sheet
self._newAttributeEqualityConstraint()
# Create a Content Existence Constraint in the test Property
# Sheet
self._newContentExistenceConstraint()
# Create all the test Properties
for operation_type in ('change', 'delete', 'assign'):
self._newStandardProperty(operation_type)
......@@ -419,7 +429,8 @@ class TestZodbPropertySheet(ERP5TypeTestCase):
# XXX: to be renamed to type_property_sheet_list as soon as
# the migration has been finished
type_zodb_property_sheet_list=('TestMigration',),
type_base_category_list=('test_category_existence_constraint',))
type_base_category_list=('test_category_existence_constraint',),
type_allowed_content_type_list=('Folder',))
# Create a test module, meaningful to force generation of
# TestMigration accessor holders and check the constraints
......@@ -448,8 +459,8 @@ class TestZodbPropertySheet(ERP5TypeTestCase):
accessor, which will run the interaction workflow trigger, on
commit at the latest
"""
self.test_module.getId()
transaction.commit()
self.test_module.getId()
def assertHasAttribute(self, obj, attribute, msg=None):
self.failIfEqual(None, getattr(obj, attribute, None),
......@@ -754,19 +765,20 @@ class TestZodbPropertySheet(ERP5TypeTestCase):
def _checkConstraint(self,
constraint_reference,
setter_function,
value):
*args,
**kw):
constraint = self._getConstraintByReference(constraint_reference)
self.failIfEqual(None, constraint)
self.assertEquals(1, len(constraint.checkConsistency(self.test_module)))
setter_function(value)
setter_function(*args, **kw)
self.assertEquals([], constraint.checkConsistency(self.test_module))
def testPropertyExistenceConstraint(self):
"""
Take the test module and check whether the Property Existence
Constraint is available. Until the property has been set to a
value, the constraint should fail
Constraint is there. Until the property has been set to a value,
the constraint should fail
"""
# See ERP5Type.Base.Base.hasProperty()
self._checkConstraint('test_property_existence_constraint',
......@@ -776,7 +788,7 @@ class TestZodbPropertySheet(ERP5TypeTestCase):
def testCategoryExistenceConstraint(self):
"""
Take the test module and check whether the Property Existence
Constraint is available. Until the category has been set to an
Constraint is there. Until the category has been set to an
existing category, the constraint should fail
"""
self._checkConstraint('test_category_existence_constraint',
......@@ -786,9 +798,9 @@ class TestZodbPropertySheet(ERP5TypeTestCase):
def testAttributeEqualityConstraint(self):
"""
Take the test module and check whether the Attribute Equality
Constraint is available. Until the attribute to be checked has
been set to its expected value, the constraint should fail. The
purpose is to test only primitive types (e.g. not list)
Constraint is there. Until the attribute to be checked has been
set to its expected value, the constraint should fail. The purpose
is to test only primitive types (e.g. not list)
"""
# As checkConsistency calls hasProperty before checking the value,
# the property to be tested has to be set at least once (whatever
......@@ -802,9 +814,9 @@ class TestZodbPropertySheet(ERP5TypeTestCase):
def testAttributeListEqualityConstraint(self):
"""
Take the test module and check whether the Attribute Equality
Constraint is available. Until the attribute to be checked has
been set to its expected value (a list of categories), the
constraint should fail. The purpose is to test only list types
Constraint is there. Until the attribute to be checked has been
set to its expected value (a list of categories), the constraint
should fail. The purpose is to test only list types
@see testAttributeEqualityConstraint
"""
......@@ -814,6 +826,18 @@ class TestZodbPropertySheet(ERP5TypeTestCase):
self.test_module.setCategoryList,
('sub_category1', 'sub_category2'))
def testContentExistenceConstraint(self):
"""
Take the test module and check whether the Content Existence
Constraint is there. Until there is at least one subobject of
'Test Module' whose Portal Type is 'Folder', the constraint should
fail
"""
self._checkConstraint('test_content_existence_constraint',
self.test_module.newContent,
id='Test Content Existence Constraint',
portal_type='Folder')
TestZodbPropertySheet = skip("ZODB Property Sheets code is not enabled yet")(
TestZodbPropertySheet)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment