# HG changeset patch # User Sylvain Thénault # Date 1492006257 -7200 # Node ID 0ff0aff4413db58cb3d84f5dc1b80e3a53277f73 # Parent f34d18d0603f06ca541706bcbc0a1c4deea650f2 [sources] Check source's url attribute value on creation/modification Similarly as for config. Now, ldap source validation is properly done there instead of at initialization time. diff -r f34d18d0603f -r 0ff0aff4413d cubicweb/hooks/syncsources.py --- a/cubicweb/hooks/syncsources.py Wed Apr 12 16:07:25 2017 +0200 +++ b/cubicweb/hooks/syncsources.py Wed Apr 12 16:10:57 2017 +0200 @@ -51,6 +51,7 @@ raise validation_error(self.entity, {('type', 'subject'): msg}) source = self.get_source(self.entity) + source.check_urls(self.entity) source.check_config(self.entity) @@ -76,5 +77,7 @@ raise validation_error(self.entity, {('name', 'subject'): msg}) source = self.get_source(self.entity) + if 'url' in self.entity.cw_edited: + source.check_urls(self.entity) if 'config' in self.entity.cw_edited: source.check_config(self.entity) diff -r f34d18d0603f -r 0ff0aff4413d cubicweb/hooks/test/unittest_syncsources.py --- a/cubicweb/hooks/test/unittest_syncsources.py Wed Apr 12 16:07:25 2017 +0200 +++ b/cubicweb/hooks/test/unittest_syncsources.py Wed Apr 12 16:10:57 2017 +0200 @@ -26,8 +26,15 @@ with self.admin_access.cnx() as cnx: source = cnx.find('CWSource').one() - with self.assertRaises(ValidationError): + with self.assertRaises(ValidationError) as cm: + source.cw_set(url=u'whatever') + self.assertIn("Configuration of the system source goes to the 'sources' file", + str(cm.exception)) + + with self.assertRaises(ValidationError) as cm: source.cw_set(config=u'whatever') + self.assertIn("Configuration of the system source goes to the 'sources' file", + str(cm.exception)) if __name__ == '__main__': diff -r f34d18d0603f -r 0ff0aff4413d cubicweb/server/sources/__init__.py --- a/cubicweb/server/sources/__init__.py Wed Apr 12 16:07:25 2017 +0200 +++ b/cubicweb/server/sources/__init__.py Wed Apr 12 16:10:57 2017 +0200 @@ -184,6 +184,17 @@ """ return cls._check_config_dict(source_entity.eid, source_entity.dictconfig) + def check_urls(self, source_entity): + """Check URL of source entity: `urls` is a string that may contain one + URL per line), and return a list of at least one validated URL. + """ + urls = source_entity.url if source_entity.url else '' + urls = [url.strip() for url in urls.splitlines() if url.strip()] + if not urls: + msg = _('specifying an URL is mandatory') + raise ValidationError(source_entity.eid, {role_name('url', 'subject'): msg}) + return urls + # source initialization / finalization ##################################### def set_schema(self, schema): @@ -200,8 +211,7 @@ """ source_entity.complete() if source_entity.url: - self.urls = [url.strip() for url in source_entity.url.splitlines() - if url.strip()] + self.urls = self.check_urls(source_entity) else: self.urls = [] diff -r f34d18d0603f -r 0ff0aff4413d cubicweb/server/sources/ldapfeed.py --- a/cubicweb/server/sources/ldapfeed.py Wed Apr 12 16:07:25 2017 +0200 +++ b/cubicweb/server/sources/ldapfeed.py Wed Apr 12 16:10:57 2017 +0200 @@ -176,18 +176,23 @@ _conn = None + def check_urls(self, source_entity): + urls = super(LDAPFeedSource, self).check_urls(source_entity) + + if len(urls) > 1: + raise ValidationError(source_entity.eid, {'url': _('can only have one url')}) + + try: + protocol, hostport = urls[0].split('://') + except ValueError: + raise ValidationError(source_entity.eid, {'url': _('badly formatted url')}) + if protocol not in PROTO_PORT: + raise ValidationError(source_entity.eid, {'url': _('unsupported protocol')}) + + return urls + def init(self, source_entity): super(LDAPFeedSource, self).init(source_entity) - if self.urls: - if len(self.urls) > 1: - raise ValidationError(source_entity.eid, {'url': _('can only have one url')}) - try: - protocol, hostport = self.urls[0].split('://') - except ValueError: - raise ValidationError(source_entity.eid, {'url': _('badly formatted url')}) - if protocol not in PROTO_PORT: - raise ValidationError(source_entity.eid, {'url': _('unsupported protocol')}) - typedconfig = self.config self.authmode = typedconfig['auth-mode'] self._authenticate = getattr(self, '_auth_%s' % self.authmode) diff -r f34d18d0603f -r 0ff0aff4413d cubicweb/server/sources/native.py --- a/cubicweb/server/sources/native.py Wed Apr 12 16:07:25 2017 +0200 +++ b/cubicweb/server/sources/native.py Wed Apr 12 16:10:57 2017 +0200 @@ -355,6 +355,12 @@ "the 'sources' file, not in the database") raise ValidationError(source_entity.eid, {role_name('config', 'subject'): msg}) + def check_urls(self, source_entity): + if source_entity.url: + msg = _("Configuration of the system source goes to " + "the 'sources' file, not in the database") + raise ValidationError(source_entity.eid, {role_name('config', 'subject'): msg}) + def add_authentifier(self, authentifier): self.authentifiers.append(authentifier) authentifier.source = self diff -r f34d18d0603f -r 0ff0aff4413d cubicweb/server/test/unittest_datafeed.py --- a/cubicweb/server/test/unittest_datafeed.py Wed Apr 12 16:07:25 2017 +0200 +++ b/cubicweb/server/test/unittest_datafeed.py Wed Apr 12 16:10:57 2017 +0200 @@ -149,6 +149,15 @@ with self.assertRaises(ValidationError) as cm: cnx.create_entity( 'CWSource', name=u'error', type=u'datafeed', parser=u'testparser', + url=None, + config=u'synchronization-interval=1min') + self.assertIn('specifying an URL is mandatory', + str(cm.exception)) + cnx.rollback() + + with self.assertRaises(ValidationError) as cm: + cnx.create_entity( + 'CWSource', name=u'error', type=u'datafeed', parser=u'testparser', url=u'ignored', config=u'synch-interval=1min') self.assertIn('unknown options synch-interval', diff -r f34d18d0603f -r 0ff0aff4413d cubicweb/server/test/unittest_ldapsource.py --- a/cubicweb/server/test/unittest_ldapsource.py Wed Apr 12 16:07:25 2017 +0200 +++ b/cubicweb/server/test/unittest_ldapsource.py Wed Apr 12 16:10:57 2017 +0200 @@ -34,7 +34,7 @@ from six import string_types from six.moves import range -from cubicweb import AuthenticationError +from cubicweb import AuthenticationError, ValidationError from cubicweb.devtools.testlib import CubicWebTC from cubicweb.devtools.httptest import get_available_port @@ -307,6 +307,33 @@ self.assertIsNotNone(pwd) self.assertTrue(str(pwd)) + def test_bad_config(self): + with self.admin_access.cnx() as cnx: + + with self.assertRaises(ValidationError) as cm: + cnx.create_entity( + 'CWSource', name=u'erroneous', type=u'ldapfeed', parser=u'ldapfeed', + url=u'ldap.com', config=CONFIG_LDAPFEED) + self.assertIn('badly formatted url', + str(cm.exception)) + cnx.rollback() + + with self.assertRaises(ValidationError) as cm: + cnx.create_entity( + 'CWSource', name=u'erroneous', type=u'ldapfeed', parser=u'ldapfeed', + url=u'http://ldap.com', config=CONFIG_LDAPFEED) + self.assertIn('unsupported protocol', + str(cm.exception)) + cnx.rollback() + + with self.assertRaises(ValidationError) as cm: + cnx.create_entity( + 'CWSource', name=u'erroneous', type=u'ldapfeed', parser=u'ldapfeed', + url=u'ldap://host1\nldap://host2', config=CONFIG_LDAPFEED) + self.assertIn('can only have one url', + str(cm.exception)) + cnx.rollback() + class LDAPGeneratePwdTC(LDAPFeedTestBase): """ diff -r f34d18d0603f -r 0ff0aff4413d cubicweb/web/test/unittest_views_cwsources.py --- a/cubicweb/web/test/unittest_views_cwsources.py Wed Apr 12 16:07:25 2017 +0200 +++ b/cubicweb/web/test/unittest_views_cwsources.py Wed Apr 12 16:10:57 2017 +0200 @@ -35,7 +35,7 @@ with self.temporary_appobjects(AParser): source = req.create_entity('CWSource', name=u'ext', type=u'datafeed', - parser=u'cw.entityxml') + parser=u'cw.entityxml', url=u'whatever') req.cnx.commit() self.threads = 0