From c89481d790d9bd9cfa54e9547cefbbe136e6d65b Mon Sep 17 00:00:00 2001
From: Arnaud Fontaine <arnaud.fontaine@nexedi.com>
Date: Fri, 26 Nov 2010 07:09:08 +0000
Subject: [PATCH] Clean up the code of ZODB Property Sheets Documents by
 setting default values in their Property Sheets

git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@40753 20353a03-c40f-0410-a6d1-a30d3c3de9de
---
 .../Core/AttributeEqualityConstraint.py       | 17 ++---------
 .../Core/CategoryExistenceConstraint.py       | 30 ++++++++-----------
 .../Core/ContentExistenceConstraint.py        | 19 ++++--------
 .../Core/PropertyExistenceConstraint.py       | 17 ++++-------
 .../AttributeEqualityConstraint.py            |  9 ++++--
 .../CategoryExistenceConstraint.py            | 14 ++++++---
 .../ContentExistenceConstraint.py             | 10 +++++--
 .../PropertyExistenceConstraint.py            | 11 +++++--
 product/ERP5Type/mixin/constraint.py          | 16 ++++++++--
 9 files changed, 69 insertions(+), 74 deletions(-)

diff --git a/product/ERP5Type/Core/AttributeEqualityConstraint.py b/product/ERP5Type/Core/AttributeEqualityConstraint.py
index 0d39be0f68..6b511a8ad8 100644
--- a/product/ERP5Type/Core/AttributeEqualityConstraint.py
+++ b/product/ERP5Type/Core/AttributeEqualityConstraint.py
@@ -32,8 +32,6 @@
 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 AttributeEqualityConstraint(ConstraintMixin):
   """
@@ -66,14 +64,6 @@ class AttributeEqualityConstraint(ConstraintMixin):
                      PropertySheet.Reference,
                      PropertySheet.AttributeEqualityConstraint)
 
-  # Define by default error messages
-  _message_id_list = ['message_invalid_attribute_value',
-                      'message_invalid_attribute_value_fixed']
-  message_invalid_attribute_value = "Attribute ${attribute_name} "\
-       "value is ${current_value} but should be ${expected_value}"
-  message_invalid_attribute_value_fixed = "Attribute ${attribute_name} "\
-       "value is ${current_value} but should be ${expected_value} (Fixed)"
-
   security.declareProtected(Permissions.AccessContentsInformation,
                             'checkConsistency')
   def checkConsistency(self, obj, fixit=False):
@@ -93,11 +83,8 @@ class AttributeEqualityConstraint(ConstraintMixin):
       identical = True
 
       # The expected value of the attribute is a TALES Expression
-      attribute_expected_value_expression = Expression(
-        self.getConstraintAttributeValue())
-
-      attribute_expected_value = attribute_expected_value_expression(
-        createExpressionContext(obj))
+      attribute_expected_value = self._getExpressionValue(
+        obj, self.getConstraintAttributeValue())
 
       attribute_value = obj.getProperty(attribute_name)
 
diff --git a/product/ERP5Type/Core/CategoryExistenceConstraint.py b/product/ERP5Type/Core/CategoryExistenceConstraint.py
index 461d96d17c..40bb07232a 100644
--- a/product/ERP5Type/Core/CategoryExistenceConstraint.py
+++ b/product/ERP5Type/Core/CategoryExistenceConstraint.py
@@ -53,17 +53,9 @@ class CategoryExistenceConstraint(ConstraintMixin):
                      PropertySheet.Reference,
                      PropertySheet.CategoryExistenceConstraint)
 
-  _message_id_list = [ 'message_category_not_set',
-                       'message_category_not_associated_with_portal_type' ]
-  message_category_not_set = "Category existence error for base"\
-      " category ${base_category}, this category is not defined"
-  message_category_not_associated_with_portal_type = "Category existence"\
-      " error for base category ${base_category}, this"\
-      " document has no such category"
-
-  def _calculateArity(self, obj, base_category, portal_type):
+  def _calculateArity(self, obj, base_category, portal_type_list):
     return len(obj.getCategoryMembershipList(base_category,
-                                             portal_type=portal_type))
+                                             portal_type=portal_type_list))
 
   security.declareProtected(Permissions.AccessContentsInformation,
                             'checkConsistency')
@@ -71,18 +63,18 @@ class CategoryExistenceConstraint(ConstraintMixin):
     """
     Check the object's consistency.
     """
-    error_list = []
     if not self.test(obj):
       return []
 
-    portal_type = self.getConstraintPortalTypeList() or ()
+    error_list = []
+    portal_type_list = self.getConstraintPortalTypeList()
     # For each attribute name, we check if defined
-    for base_category in self.getConstraintBaseCategoryList() or ():
+    for base_category in self.getConstraintBaseCategoryList():
       mapping = dict(base_category=base_category)
       # Check existence of base category
       if base_category not in obj.getBaseCategoryList():
         error_message = 'message_category_not_associated_with_portal_type'
-      elif self._calculateArity(obj, base_category, portal_type) == 0:
+      elif self._calculateArity(obj, base_category, portal_type_list) == 0:
         error_message = 'message_category_not_set'
       else:
         error_message = None
@@ -91,7 +83,9 @@ class CategoryExistenceConstraint(ConstraintMixin):
       if error_message:
         error_list.append(
           self._generateError(obj,
-                              self._getMessage(error_message), mapping))
+                              self._getMessage(error_message),
+                              mapping))
+
     return error_list
 
 class CategoryAcquiredExistenceConstraint(CategoryExistenceConstraint):
@@ -101,6 +95,6 @@ class CategoryAcquiredExistenceConstraint(CategoryExistenceConstraint):
   Sheets (filesystem Property Sheets rely on
   Products.ERP5Type.Constraint.CategoryExistence instead).
   """
-  def _calculateArity(self, obj, base_category, portal_type):
-    return len(obj.getAcquiredCategoryMembershipList(base_category,
-                                             portal_type=portal_type))
+  def _calculateArity(self, obj, base_category, portal_type_list):
+    return len(obj.getAcquiredCategoryMembershipList(
+      base_category, portal_type=portal_type_list))
diff --git a/product/ERP5Type/Core/ContentExistenceConstraint.py b/product/ERP5Type/Core/ContentExistenceConstraint.py
index 955563eb3b..06771b3574 100644
--- a/product/ERP5Type/Core/ContentExistenceConstraint.py
+++ b/product/ERP5Type/Core/ContentExistenceConstraint.py
@@ -1,7 +1,8 @@
 ##############################################################################
 #
-# Copyright (c) 2006 Nexedi SARL and Contributors. All Rights Reserved.
-#                    Romain Courteaud <romain@nexedi.com>
+# Copyright (c) 2006-2010 Nexedi SARL and Contributors. All Rights Reserved.
+#                         Romain Courteaud <romain@nexedi.com>
+#                         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
@@ -29,8 +30,6 @@
 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):
   """
@@ -63,14 +62,6 @@ class ContentExistenceConstraint(ConstraintMixin):
                      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
@@ -79,8 +70,8 @@ class ContentExistenceConstraint(ConstraintMixin):
     if not self.test(obj):
       return []
 
-    portal_type = Expression(self.getConstraintPortalType())(
-      createExpressionContext(obj))
+    portal_type = self._getExpressionValue(obj,
+                                           self.getConstraintPortalType())
 
     # If there is at least one subobject with the given Portal Type,
     # then return now
diff --git a/product/ERP5Type/Core/PropertyExistenceConstraint.py b/product/ERP5Type/Core/PropertyExistenceConstraint.py
index a5794ae65f..5791af3694 100644
--- a/product/ERP5Type/Core/PropertyExistenceConstraint.py
+++ b/product/ERP5Type/Core/PropertyExistenceConstraint.py
@@ -59,26 +59,18 @@ class PropertyExistenceConstraint(ConstraintMixin):
                      PropertySheet.Reference,
                      PropertySheet.PropertyExistenceConstraint)
 
-  # Define by default error messages
-  _message_id_list = ['message_no_such_property',
-                      'message_property_not_set']
-  message_no_such_property =  "Property existence error for property "\
-            "${property_id}, this document has no such property"
-  message_property_not_set = "Property existence error for property "\
-            "${property_id}, this property is not defined"
-
   security.declareProtected(Permissions.AccessContentsInformation,
                             'checkConsistency')
   def checkConsistency(self, obj, fixit=0):
     """
     Check the object's consistency.
     """
-    error_list = []
     if not self.test(obj):
       return []
 
+    error_list = []
     # For each attribute name, we check if defined
-    for property_id in self.getConstraintPropertyList() or ():
+    for property_id in self.getConstraintPropertyList():
       # Check existence of property
       mapping = dict(property_id=property_id)
       if not obj.hasProperty(property_id):
@@ -91,6 +83,7 @@ class PropertyExistenceConstraint(ConstraintMixin):
         error_message_id = None
 
       if error_message_id:
-        error_list.append(self._generateError(obj,
-                     self._getMessage(error_message_id), mapping))
+        error_list.append(self._generateError(
+          obj, self._getMessage(error_message_id), mapping))
+
     return error_list
diff --git a/product/ERP5Type/PropertySheet/AttributeEqualityConstraint.py b/product/ERP5Type/PropertySheet/AttributeEqualityConstraint.py
index 8a2b98ae9a..c846bb8790 100644
--- a/product/ERP5Type/PropertySheet/AttributeEqualityConstraint.py
+++ b/product/ERP5Type/PropertySheet/AttributeEqualityConstraint.py
@@ -40,8 +40,13 @@ class AttributeEqualityConstraint:
             'description' : 'Valid values of the Attribute' },
         {   'id': 'message_invalid_attribute_value',
             'type': 'string',
-            'description' : 'Error message when the attribute value is invalid' },
+            'description' : 'Error message when the attribute value is invalid',
+            'default': 'Attribute ${attribute_name} value is ${current_value} '\
+                       'but should be ${expected_value}' },
         {   'id': 'message_invalid_attribute_value_fixed',
             'type': 'string',
-            'description' : 'Error message when the attribute value is invalid but has been fixed' },
+            'description' : 'Error message when the attribute value is '\
+                            'invalid but has been fixed',
+            'default': 'Attribute ${attribute_name} value is ${current_value} '\
+                       'but should be ${expected_value} (Fixed)'},
         )
diff --git a/product/ERP5Type/PropertySheet/CategoryExistenceConstraint.py b/product/ERP5Type/PropertySheet/CategoryExistenceConstraint.py
index 3a42a53ccf..0e6fb79160 100644
--- a/product/ERP5Type/PropertySheet/CategoryExistenceConstraint.py
+++ b/product/ERP5Type/PropertySheet/CategoryExistenceConstraint.py
@@ -33,14 +33,20 @@ class CategoryExistenceConstraint:
     _properties = (
         {   'id': 'constraint_base_category',
             'type': 'lines',
-            'description' : 'Categories to check the existence for' },
+            'description' : 'Categories to check the existence for',
+            'default': () },
         {   'id': 'constraint_portal_type',
             'type': 'lines',
-            'description' : 'Portal type' },
+            'description' : 'Portal types',
+            'default': () },
         {   'id': 'message_category_not_set',
             'type': 'string',
-            'description' : 'Error message when the category is not defined' },
+            'description' : 'Error message when the category is not defined',
+            'default': 'Category existence error for base category '\
+                       '${base_category}, this category is not defined' },
         {   'id': 'message_category_not_associated_with_portal_type',
             'type': 'string',
-            'description' : 'Error message when there is no such category' },
+            'description' : 'Error message when there is no such category',
+            'default': 'Category existence error for base category '\
+                       '${base_category}, this document has no such category' },
         )
diff --git a/product/ERP5Type/PropertySheet/ContentExistenceConstraint.py b/product/ERP5Type/PropertySheet/ContentExistenceConstraint.py
index de964dc1f0..a905f5349b 100644
--- a/product/ERP5Type/PropertySheet/ContentExistenceConstraint.py
+++ b/product/ERP5Type/PropertySheet/ContentExistenceConstraint.py
@@ -34,12 +34,16 @@ class ContentExistenceConstraint:
         # TALES Expression
         {   'id': 'constraint_portal_type',
             'type': 'string',
-            'description' : 'Portal type',
+            'description' : 'Portal types',
             'default': 'python: ()' },
         {   'id': 'message_no_subobject',
             'type': 'string',
-            'description' : 'Error message when there is no subobject' },
+            'description' : 'Error message when there is no subobject',
+            'default': 'The document does not contain any subobject' },
         {   'id': 'message_no_subobject_portal_type',
             'type': 'string',
-            'description' : 'Error message when there is no subobject of the given portal type' },
+            'description' : 'Error message when there is no subobject of the '\
+                            'given portal type',
+            'default': 'The document does not contain any subobject of portal '\
+                       'portal type ${portal_type}' },
         )
diff --git a/product/ERP5Type/PropertySheet/PropertyExistenceConstraint.py b/product/ERP5Type/PropertySheet/PropertyExistenceConstraint.py
index 9861a73977..09023ad91f 100644
--- a/product/ERP5Type/PropertySheet/PropertyExistenceConstraint.py
+++ b/product/ERP5Type/PropertySheet/PropertyExistenceConstraint.py
@@ -33,11 +33,16 @@ class PropertyExistenceConstraint:
     _properties = (
         {   'id': 'constraint_property',
             'type': 'lines',
-            'description' : 'Properties to check the existence for' },
+            'description' : 'Properties to check the existence for',
+            'default': () },
         {   'id': 'message_no_such_property',
             'type': 'string',
-            'description' : 'Error message when there is no such property' },
+            'description' : 'Error message when there is no such property',
+            'default': 'Property existence error for property ${property_id}, '\
+                       'this document has no such property' },
         {   'id': 'message_property_not_set',
             'type': 'string',
-            'description' : 'Error message when the property is not set' },
+            'description' : 'Error message when the property is not set',
+            'default': 'Property existence error for property ${property_id}, '\
+                       'this property is not defined' },
         )
diff --git a/product/ERP5Type/mixin/constraint.py b/product/ERP5Type/mixin/constraint.py
index 2ae8ecdbe9..5dbaf52158 100644
--- a/product/ERP5Type/mixin/constraint.py
+++ b/product/ERP5Type/mixin/constraint.py
@@ -35,7 +35,8 @@ from zope.interface import implements
 from Products.ERP5Type.Core.Predicate import Predicate
 from AccessControl import ClassSecurityInfo
 from Products.ERP5Type import Permissions
-from Products.ERP5Type.Utils import UpperCase
+from Products.ERP5Type.Utils import UpperCase, createExpressionContext
+from Products.CMFCore.Expression import Expression
 
 class ConstraintMixin(Predicate):
   """
@@ -54,8 +55,6 @@ class ConstraintMixin(Predicate):
   __allow_access_to_unprotected_subobjects__ = 1
   implements( IConstraint, )
 
-  _message_id_list = []
-
   def _getMessage(self, message_id):
     """
     Get the message corresponding to this message_id.
@@ -101,3 +100,14 @@ class ConstraintMixin(Predicate):
     XXX: remove as soon as the code is stable
     """
     return self.asContext()
+
+  def _getExpressionValue(self, obj, expression_string):
+    """
+    Get the Python value from an Expression string, but check before
+    whether it is None as a getter may returns the default value which
+    could be None
+    """
+    if expression_string is None:
+      return None
+
+    return Expression(expression_string)(createExpressionContext(obj))
-- 
2.30.9