diff --git a/.travis.yml b/.travis.yml index 4b84c11c..28357e91 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,7 +22,7 @@ env: EXCLUDE="xml_test_output" matrix: - LINT_CHECK="1" - - ODOO_REPO="valdecdev/odoo" RUN_PIPELINE="1" TESTS="1" INCLUDE="nh_odoo_fixes,nh_activity,nh_clinical" + - ODOO_REPO="valdecdev/odoo" RUN_PIPELINE="1" TESTS="1" INCLUDE="nh_odoo_fixes,nh_activity,nh_clinical,nh_clinical_ldap" VERSION="openeobs-8-12" virtualenv: system_site_packages: true diff --git a/nh_clinical_ldap/__init__.py b/nh_clinical_ldap/__init__.py new file mode 100644 index 00000000..d1a5f34a --- /dev/null +++ b/nh_clinical_ldap/__init__.py @@ -0,0 +1,3 @@ +# Part of NHClinical. See LICENSE file for full copyright and licensing details +# -*- coding: utf-8 -*- +from . import auth_ldap_extension diff --git a/nh_clinical_ldap/__openerp__.py b/nh_clinical_ldap/__openerp__.py new file mode 100644 index 00000000..1ed7c5b8 --- /dev/null +++ b/nh_clinical_ldap/__openerp__.py @@ -0,0 +1,21 @@ +# Part of NHClinical. See LICENSE file for full copyright and licensing details +# -*- coding: utf-8 -*- +{ + 'name': 'NH Clinical LDAP', + 'version': '0.1', + 'category': 'Base', + 'license': 'AGPL-3', + 'summary': 'NH LDAP Extension', + 'description': """ LDAP for NH Clinical """, + 'author': 'Neova Health', + 'website': 'http://www.neovahealth.co.uk/', + 'depends': ['auth_ldap', 'nh_clinical'], + 'data': [], + 'demo': [], + 'images': [], + 'css': [], + 'test': [], + 'application': True, + 'installable': True, + 'active': False, +} diff --git a/nh_clinical_ldap/auth_ldap_extension.py b/nh_clinical_ldap/auth_ldap_extension.py new file mode 100644 index 00000000..3b8d494b --- /dev/null +++ b/nh_clinical_ldap/auth_ldap_extension.py @@ -0,0 +1,50 @@ +# Part of NHClinical. See LICENSE file for full copyright and licensing details +# -*- coding: utf-8 -*- +from openerp.osv import orm +import logging + +_logger = logging.getLogger(__name__) + + +class NHClinicalLDAPExtension(orm.Model): + + _name = 'res.company.ldap' + _inherit = 'res.company.ldap' + + def map_ldap_attributes(self, cr, uid, conf, login, ldap_entry, + context=None): + """ + Compose values for a new resource of model res_users, + based upon the retrieved ldap entry and the LDAP settings. + + :param dict conf: LDAP configuration + :param login: the new user's login + :param tuple ldap_entry: single LDAP result (dn, attrs) + :return: parameters for a new resource of model res_users + :rtype: dict + """ + + category_pool = self.pool['res.partner.category'] + location_pool = self.pool['nh.clinical.location'] + pos_pool = self.pool['nh.clinical.pos'] + + hospital = location_pool.search(cr, uid, [['usage', '=', 'hospital']], + context=context) + pos = pos_pool.search(cr, uid, [['location_id', 'in', hospital]], + context=context) + hca_group = category_pool.search(cr, uid, [['name', '=', 'HCA']], + context=context) + + if len(ldap_entry) < 2: + raise ValueError('LDAP Entry does not contain second element') + if len(ldap_entry[1].get('cn')) < 1: + raise ValueError('LDAP Entry CN does not contain elements') + + values = {'name': ldap_entry[1]['cn'][0], + 'login': login, + 'company_id': conf.get('company'), + 'ward_ids': [[6, 0, []]], + 'pos_ids': [[6, 0, pos]], + 'category_id': [[6, 0, hca_group]] + } + return values diff --git a/nh_clinical_ldap/tests/__init__.py b/nh_clinical_ldap/tests/__init__.py new file mode 100644 index 00000000..75e97be5 --- /dev/null +++ b/nh_clinical_ldap/tests/__init__.py @@ -0,0 +1 @@ +from . import test_map_ldap_extension diff --git a/nh_clinical_ldap/tests/test_map_ldap_extension.py b/nh_clinical_ldap/tests/test_map_ldap_extension.py new file mode 100644 index 00000000..18fb9b7f --- /dev/null +++ b/nh_clinical_ldap/tests/test_map_ldap_extension.py @@ -0,0 +1,113 @@ +from openerp.tests.common import SingleTransactionCase + + +class TestMapLDAPExtension(SingleTransactionCase): + + @classmethod + def setUpClass(cls): + super(TestMapLDAPExtension, cls).setUpClass() + cls.category_pool = cls.registry('res.partner.category') + cls.location_pool = cls.registry('nh.clinical.location') + cls.pos_pool = cls.registry('nh.clinical.pos') + cls.ldap_pool = cls.registry('res.company.ldap') + + cls.ldap_entry = [ + None, + { + 'cn': [ + 'Test User' + ] + } + ] + + cls.conf = { + 'company': 1 + } + + def mock_category_search(*args, **kwargs): + return [1] + + def mock_location_search(*args, **kwargs): + context = kwargs.get('context') + test = context.get('test') if context else '' + if test == 'test_empty_location': + return [] + return [666] + + def mock_pos_search(*args, **kwargs): + context = kwargs.get('context') + test = context.get('test') if context else '' + if test == 'test_location': + global location_passed + location_passed = args[3] + if test == 'test_empty_location': + global empty_location + empty_location = args[3] + return [1] + + cls.category_pool._patch_method('search', mock_category_search) + cls.location_pool._patch_method('search', mock_location_search) + cls.pos_pool._patch_method('search', mock_pos_search) + + @classmethod + def tearDownClass(cls): + cls.category_pool._revert_method('search') + cls.location_pool._revert_method('search') + cls.pos_pool._revert_method('search') + super(TestMapLDAPExtension, cls).tearDownClass() + + def test_hospital_passed_to_pos(self): + """ + TEst that when a hospital is found it is then used to find the POS for + that hospital + """ + cr, uid = self.cr, self.uid + self.ldap_pool.map_ldap_attributes( + cr, uid, self.conf, 'test', self.ldap_entry, + context={'test': 'test_location'}) + self.assertEqual(location_passed[0][2], [666]) + + def test_empty_hospital_passed_to_pos(self): + """ + TEst that when a hospital is not found it is then used to find the POS + for that hospital + """ + cr, uid = self.cr, self.uid + self.ldap_pool.map_ldap_attributes( + cr, uid, self.conf, 'test', self.ldap_entry, + context={'test': 'test_empty_location'}) + self.assertEqual(empty_location, [['location_id', 'in', []]]) + + def test_pos(self): + """ + TEst that on POS found it then in the returned dict + """ + cr, uid = self.cr, self.uid + vals = self.ldap_pool.map_ldap_attributes( + cr, uid, self.conf, 'test', self.ldap_entry, + context={'test': 'test_pos'}) + self.assertEqual(vals.get('pos_ids'), [[6, 0, [1]]]) + + def test_raises_on_invalid_ldap_entry(self): + """ + TEst it raises value error when trying to map a non-conformant LDAP + entry + """ + cr, uid = self.cr, self.uid + with self.assertRaises(ValueError) as ldap_err: + self.ldap_pool.map_ldap_attributes( + cr, uid, self.conf, 'test', [0]) + self.assertEqual(ldap_err.exception.message, + 'LDAP Entry does not contain second element') + + def test_raises_on_invalid_ldap_entry_cn(self): + """ + TEst it raises value error when trying to map a non-conformant LDAP + entry + """ + cr, uid = self.cr, self.uid + with self.assertRaises(ValueError) as ldap_err: + self.ldap_pool.map_ldap_attributes( + cr, uid, self.conf, 'test', [None, {'cn': []}]) + self.assertEqual(ldap_err.exception.message, + 'LDAP Entry CN does not contain elements') diff --git a/requirements.txt b/requirements.txt index 05c9b5e1..df32c9ac 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,3 +3,4 @@ mock==1.3.0 pylint==1.4.4 coverage==4.0.3 fake-factory==0.5.1 +python-ldap==2.4.19