changeset a2f811ed0e99 in trytond:default
details: https://hg.tryton.org/trytond?cmd=changeset;node=a2f811ed0e99
description:
        Forbid all white spaces except space in Char field

        They can not be displayed by all clients (nor OS).
        But also they can be trimmed automatically by web input which breaks 
comparison
        against changes.

        issue9248
        review312681002
diffstat:

 CHANGELOG                        |   2 ++
 trytond/ir/message.xml           |   3 +++
 trytond/model/exceptions.py      |   4 +++-
 trytond/model/fields/char.py     |   1 +
 trytond/model/fields/text.py     |   1 +
 trytond/model/modelstorage.py    |  18 ++++++++++++++++++
 trytond/tests/test_field_char.py |  13 ++++++++++++-
 7 files changed, 40 insertions(+), 2 deletions(-)

diffs (127 lines):

diff -r 4fcc1d6a97d5 -r a2f811ed0e99 CHANGELOG
--- a/CHANGELOG Mon Nov 02 15:37:54 2020 +0100
+++ b/CHANGELOG Thu Nov 05 23:58:15 2020 +0100
@@ -1,3 +1,5 @@
+* Forbid all white spaces except space in Char field
+
 Version 5.8.0 - 2020-11-02
 * Bug fixes (see mercurial logs for details)
 * Remove support for Python 3.5
diff -r 4fcc1d6a97d5 -r a2f811ed0e99 trytond/ir/message.xml
--- a/trytond/ir/message.xml    Mon Nov 02 15:37:54 2020 +0100
+++ b/trytond/ir/message.xml    Thu Nov 05 23:58:15 2020 +0100
@@ -150,6 +150,9 @@
         <record model="ir.message" id="msg_digits_validation_record">
             <field name="text">The number of digits in the value "%(value)s" 
for field "%(field)s" in "%(model)s" exceeds the limit of "%(digits)i".</field>
         </record>
+        <record model="ir.message" id="msg_forbidden_char_validation_record">
+            <field name="text">The value "%(value)s" for field "%(field)s" in 
"%(model)s" contains some invalid chars "%(chars)".</field>
+        </record>
         <record model="ir.message" id="msg_selection_validation_record">
             <field name="text">The value "%(value)s" for field "%(field)s" in 
"%(model)s" is not one of the allowed options.</field>
         </record>
diff -r 4fcc1d6a97d5 -r a2f811ed0e99 trytond/model/exceptions.py
--- a/trytond/model/exceptions.py       Mon Nov 02 15:37:54 2020 +0100
+++ b/trytond/model/exceptions.py       Thu Nov 05 23:58:15 2020 +0100
@@ -3,7 +3,8 @@
 
 from .modelstorage import (AccessError, ImportDataError, ValidationError,
     DomainValidationError, RequiredValidationError, SizeValidationError,
-    DigitsValidationError, SelectionValidationError, TimeFormatValidationError)
+    DigitsValidationError, ForbiddenCharValidationError,
+    SelectionValidationError, TimeFormatValidationError)
 from .modelsql import ForeignKeyError, SQLConstraintError
 from .modelview import AccessButtonError
 from .tree import RecursionError
@@ -18,6 +19,7 @@
     RecursionError,
     RequiredValidationError,
     SQLConstraintError,
+    ForbiddenCharValidationError,
     SelectionValidationError,
     SizeValidationError,
     TimeFormatValidationError,
diff -r 4fcc1d6a97d5 -r a2f811ed0e99 trytond/model/fields/char.py
--- a/trytond/model/fields/char.py      Mon Nov 02 15:37:54 2020 +0100
+++ b/trytond/model/fields/char.py      Thu Nov 05 23:58:15 2020 +0100
@@ -13,6 +13,7 @@
     '''
     _type = 'char'
     _py_type = str
+    forbidden_chars = '\t\n\r\x0b\x0c'
 
     def __init__(self, string='', size=None, help='', required=False,
             readonly=False, domain=None, states=None, translate=False,
diff -r 4fcc1d6a97d5 -r a2f811ed0e99 trytond/model/fields/text.py
--- a/trytond/model/fields/text.py      Mon Nov 02 15:37:54 2020 +0100
+++ b/trytond/model/fields/text.py      Thu Nov 05 23:58:15 2020 +0100
@@ -9,3 +9,4 @@
     '''
     _type = 'text'
     _sql_type = 'TEXT'
+    forbidden_chars = ''
diff -r 4fcc1d6a97d5 -r a2f811ed0e99 trytond/model/modelstorage.py
--- a/trytond/model/modelstorage.py     Mon Nov 02 15:37:54 2020 +0100
+++ b/trytond/model/modelstorage.py     Thu Nov 05 23:58:15 2020 +0100
@@ -61,6 +61,10 @@
     pass
 
 
+class ForbiddenCharValidationError(ValidationError):
+    pass
+
+
 class SelectionValidationError(ValidationError):
     pass
 
@@ -1271,6 +1275,20 @@
                             digits_test(getattr(record, field_name),
                                 field.digits, field_name)
 
+                if hasattr(field, 'forbidden_chars'):
+                    for record in records:
+                        value = getattr(record, field_name)
+                        if value and any(
+                                c in value for c in field.forbidden_chars):
+                            error_args = cls.__names__(field_name)
+                            error_args['value'] = value
+                            error_args['chars'] = ','.join(
+                                repr(c) for c in field.forbidden_chars
+                                if c in value)
+                            raise ForbiddenCharValidationError(gettext(
+                                    'ir.msg_forbidden_char_validation_record',
+                                    **error_args))
+
                 # validate selection
                 if hasattr(field, 'selection') and field.selection:
                     if isinstance(field.selection, (tuple, list)):
diff -r 4fcc1d6a97d5 -r a2f811ed0e99 trytond/tests/test_field_char.py
--- a/trytond/tests/test_field_char.py  Mon Nov 02 15:37:54 2020 +0100
+++ b/trytond/tests/test_field_char.py  Thu Nov 05 23:58:15 2020 +0100
@@ -6,7 +6,8 @@
 from sql import Literal
 
 from trytond import backend
-from trytond.model.exceptions import RequiredValidationError
+from trytond.model.exceptions import (
+    RequiredValidationError, ForbiddenCharValidationError)
 from trytond.pool import Pool
 from trytond.tests.test_tryton import activate_module, with_transaction
 from trytond.transaction import Transaction
@@ -411,6 +412,16 @@
                         }])
 
     @with_transaction()
+    def test_create_invalid_char(self):
+        "Test create char with invalid char"
+        Char = Pool().get('test.char')
+
+        with self.assertRaises(ForbiddenCharValidationError):
+            Char.create([{
+                        'char': "foo\nbar",
+                        }])
+
+    @with_transaction()
     def test_write(self):
         "Test write char"
         Char = Pool().get('test.char')

Reply via email to