Skip to content

Commit

Permalink
Merge commit 'refs/pull/11/head' of github.com:acsone/alfodoo into 9.…
Browse files Browse the repository at this point in the history
…0-slg_master
  • Loading branch information
lmignon committed Oct 26, 2016
2 parents 61951f7 + 003d4b7 commit 6aa9d80
Show file tree
Hide file tree
Showing 7 changed files with 137 additions and 14 deletions.
3 changes: 3 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
9.0.?.?.? (?)
~~~~~~~~~~~~~

* Improvement: The name used to create the folder in CMIS is automatically sanitized.
This feature can be deactivated by a flag on the backend configuration and it's also
possible to specify the character to use as replacement to invalid characters.
* Fix JS error when trying to order by *last modification date.*


Expand Down
1 change: 1 addition & 0 deletions cmis_field/__openerp__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
'cmis'
],
'data': [
'views/cmis_backend_view.xml'
],
'installable': True,
}
22 changes: 13 additions & 9 deletions cmis_field/fields/cmis_folder.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,10 @@ def _create_in_cmis(self, records, backend):
repo = backend.get_cmis_repository()
for record in records:
name = names[record.id]
backend.is_valid_cmis_name(name, raise_if_invalid=True)
if backend.enable_sanitize_cmis_name:
name = backend.sanitize_cmis_name(name)
else:
backend.is_valid_cmis_name(name, raise_if_invalid=True)
parent = parents[record.id]
props = properties[record.id] or {}
value = repo.createFolder(
Expand Down Expand Up @@ -171,9 +174,9 @@ def get_create_parents(self, records, backend):
if not callable(fct):
fct = getattr(records, fct)
return fct(self, backend)
path = self.get_default_parent_path(records, backend)
parent_cmis_object = backend.get_folder_by_path(
path, create_if_not_found=True)
path_parts = self.get_default_parent_path_parts(records, backend)
parent_cmis_object = backend.get_folder_by_path_parts(
path_parts, create_if_not_found=True)
return dict.fromkeys(records.ids, parent_cmis_object)

def get_create_properties(self, records, backend):
Expand All @@ -193,10 +196,11 @@ def get_create_properties(self, records, backend):
return fct(self, backend)
return dict.fromkeys(records.ids, None)

def get_default_parent_path(self, records, backend):
"""Return the default path into the cmis container to use as parent
on folder create. By default:
def get_default_parent_path_parts(self, records, backend):
"""Return the default path parts into the cmis container to use as
parent on folder create. By default:
backend.initial_directory_write / record._name
"""
return '/'.join([backend.initial_directory_write,
records[0]._name.replace('.', '_')])
path_parts = backend.initial_directory_write.split('/')
path_parts.append(records[0]._name.replace('.', '_'))
return path_parts
65 changes: 61 additions & 4 deletions cmis_field/models/cmis_backend.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,41 @@
# -*- coding: utf-8 -*-
# Copyright 2016 ACSONE SA/NV
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

from openerp import api, models, _
from openerp.exceptions import UserError
import re
from openerp import api, fields, models, _
from openerp.exceptions import UserError, ValidationError


CMIS_NAME_INVALID_CHARS = r'\/:*?"<>|'
CMIS_NAME_INVALID_CHARS_RX = '[' + re.escape(CMIS_NAME_INVALID_CHARS) + ']'


class CmisBackend(models.Model):

_inherit = 'cmis.backend'

@api.constrains('sanitize_replace_char')
def _check_sanitize_replace_char(self):
for rec in self:
rc = self.sanitize_replace_char
if rc and re.findall(CMIS_NAME_INVALID_CHARS_RX, rc):
raise ValidationError(
_("The character to use as replacement can not be one of"
"'%s'") % CMIS_NAME_INVALID_CHARS
)

enable_sanitize_cmis_name = fields.Boolean(
'Sanitize name on content creation?',
help='If checked, the name of the CMIS content created by the '
'CMIS fields will be sanitized by replacing the characters not '
'supported in a cmis:name with the one specified.',
default=True)
sanitize_replace_char = fields.Char(
'Replacement char',
help='Character used as replacement of invalid characters found in'
'the value to use as cmis:name by the sanitize method',
default='_')

@api.model
def _get_web_description(self, record):
""" Return the desciption of backend record to be included into the
Expand Down Expand Up @@ -53,10 +76,44 @@ def get_by_name(self, name, raise_if_not_found=True):

@api.model
def is_valid_cmis_name(self, name, raise_if_invalid=False):
if any(c in name for c in CMIS_NAME_INVALID_CHARS):
if re.findall(CMIS_NAME_INVALID_CHARS_RX, name) or \
name.startswith(' ') or \
name.endswith(' '):
if not raise_if_invalid:
return False
raise UserError(_("%s is not a valid name.\n"
"The following chars are not allowed %s") %
(name, CMIS_NAME_INVALID_CHARS))
return True

@api.multi
def sanitize_cmis_name(self, value, replace_char=None):
"""Replace chars not allowed in cmis by the value of replace_char.
If replace_char is None, the character used to subsitute invalid chars
is the one defined by the sanitize_replace_char field
"""
self.ensure_one()
if replace_char is None:
replace_char = self.sanitize_replace_char or ''
return re.sub(CMIS_NAME_INVALID_CHARS_RX, replace_char,
value.strip()).strip()

@api.multi
def sanitize_cmis_names(self, values, replace_char=None):
"""Sanitize a list of values
"""
return [self.sanitize_cmis_name(v, replace_char) for v in values]

@api.multi
def get_folder_by_path_parts(self, path_parts, create_if_not_found=True,
cmis_parent_objectid=None):
"""Return the cmis object for the specified path parts.
The path is build from path_parts where each part is sanitized if
`enable_sanitize_cmis_name` is True on the backend instance
"""
self.ensure_one()
if self.enable_sanitize_cmis_name:
path_parts = self.sanitize_cmis_names(path_parts)
path = "/".join(path_parts)
return self.get_folder_by_path(
path, create_if_not_found, cmis_parent_objectid)
21 changes: 20 additions & 1 deletion cmis_field/tests/test_cmis_backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

from openerp.tests import common
from openerp.exceptions import UserError
from openerp.exceptions import UserError, ValidationError


class TestCmisBackend(common.SavepointCase):
Expand Down Expand Up @@ -32,3 +32,22 @@ def test_is_valid_cmis_name(self):
with self.assertRaises(UserError):
backend.is_valid_cmis_name(r'my\/:*?"<>| directory',
raise_if_invalid=True)

def test_sanitize_cmis_name(self):
self.backend_instance.sanitize_replace_char = "_"
sanitized = self.backend_instance.sanitize_cmis_name('m/y dir*', '_')
self.assertEqual(sanitized, 'm_y dir_')
sanitized = self.backend_instance.sanitize_cmis_name('m/y dir*', None)
self.assertEqual(sanitized, 'm_y dir_')
sanitized = self.backend_instance.sanitize_cmis_name('m/y dir*', '')
self.assertEqual(sanitized, 'my dir')
sanitized = self.backend_instance.sanitize_cmis_name('m/y dir*', '-')
self.assertEqual(sanitized, 'm-y dir-')
sanitized = self.backend_instance.sanitize_cmis_name('/y dir*', ' ')
self.assertEqual(sanitized, 'y dir')
with self.assertRaises(ValidationError):
self.backend_instance.sanitize_replace_char = "/"

sanitized = self.backend_instance.sanitize_cmis_names(
['/y dir*', 'sub/dir'], ' ')
self.assertEqual(sanitized, ['y dir', 'sub dir'])
23 changes: 23 additions & 0 deletions cmis_field/tests/test_fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ def test_cmis_folder_default_create(self):

def test_cmis_folder_create_invalid_name(self):
inst = self.env['cmis.test.model'].create({'name': 'folder /'})
self.cmis_backend.enable_sanitize_cmis_name = False
with mock.patch("openerp.addons.cmis.models.cmis_backend."
"CmisBackend.get_cmis_repository"
) as mocked_get_repository:
Expand All @@ -83,6 +84,28 @@ def test_cmis_folder_create_invalid_name(self):
# field. As result the value must be set on the given record
with self.assertRaises(UserError):
inst._fields['cmis_folder'].create_value(inst)
inst.name = ' toto '
with self.assertRaises(UserError):
inst._fields['cmis_folder'].create_value(inst)

def test_cmis_folder_create_sanitize_name(self):
inst = self.env['cmis.test.model'].create({'name': ' /folder/'})
with mock.patch("openerp.addons.cmis.models.cmis_backend."
"CmisBackend.get_cmis_repository"
) as mocked_get_repository:
mocked_cmis_repository = mock.MagicMock()
mocked_get_repository.return_value = mocked_cmis_repository
new_mocked_cmis_folder = mock.MagicMock()
mocked_cmis_repository.createFolder.return_value = \
new_mocked_cmis_folder
mocked_cmis_repository.getObjectByPath.return_value = 'root_id'
new_mocked_cmis_folder.getObjectId.return_value = 'cmis_id'

# check the value initialization using the method defined on the
# field. As result the value must be set on the given record
inst._fields['cmis_folder'].create_value(inst)
mocked_cmis_repository.createFolder.assert_called_once_with(
'root_id', '_folder_', {})

def test_cmis_folder_create_x_get(self):
# Test the use of methods specified on the field to get the
Expand Down
16 changes: 16 additions & 0 deletions cmis_field/views/cmis_backend_view.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>

<record id="cmis_backend_form_view" model="ir.ui.view">
<field name="name">cmis.backend.form (cmis_field)</field>
<field name="model">cmis.backend</field>
<field name="inherit_id" ref="cmis.cmis_backend_form_view"/>
<field name="arch" type="xml">
<field name="location" position="after">
<field name="enable_sanitize_cmis_name" colspan="2"/>
<field name="sanitize_replace_char" colspan="2" attrs="{'invisible': [('enable_sanitize_cmis_name', '=', False)]}"/>
</field>
</field>
</record>

</odoo>

0 comments on commit 6aa9d80

Please sign in to comment.