From fc1097763c8d9bdb3be42bbd43c037aab59f1b6d Mon Sep 17 00:00:00 2001 From: kindly Date: Thu, 10 Oct 2013 20:55:23 +0100 Subject: [PATCH 01/13] [#1267] fix url for by faking routes threadlocal --- ckan/lib/cli.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/ckan/lib/cli.py b/ckan/lib/cli.py index 14c217ed096..5d13da6638b 100644 --- a/ckan/lib/cli.py +++ b/ckan/lib/cli.py @@ -10,6 +10,8 @@ import ckan.include.rcssmin as rcssmin import ckan.lib.fanstatic_resources as fanstatic_resources import sqlalchemy as sa +import urlparse +import routes import paste.script from paste.registry import Registry @@ -99,6 +101,12 @@ def _load_config(self): self.translator_obj = MockTranslator() self.registry.register(pylons.translator, self.translator_obj) + ## give routes enough information to run url_for + parsed = urlparse.urlparse(conf.get('ckan.site_url', 'http://0.0.0.0')) + request_config = routes.request_config() + request_config.host = parsed.netloc + parsed.path + request_config.protocol = parsed.scheme + def _setup_app(self): cmd = paste.script.appinstall.SetupCommand('setup-app') cmd.run([self.filename]) From 7ab8bd9e9de8ff02a177db571e800d7383816c77 Mon Sep 17 00:00:00 2001 From: Samuele Santi Date: Fri, 18 Oct 2013 12:48:23 +0200 Subject: [PATCH 02/13] pep8 --- setup.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/setup.py b/setup.py index 3f5115bfa8f..04fc1647fec 100644 --- a/setup.py +++ b/setup.py @@ -5,7 +5,8 @@ use_setuptools() from setuptools import setup, find_packages -from ckan import __version__, __description__, __long_description__, __license__ +from ckan import (__version__, __description__, __long_description__, + __license__) setup( name='ckan', @@ -16,7 +17,7 @@ url='http://ckan.org/', description=__description__, keywords='data packaging component tool server', - long_description =__long_description__, + long_description=__long_description__, zip_safe=False, packages=find_packages(exclude=['ez_setup']), namespace_packages=['ckanext', 'ckanext.stats'], @@ -28,7 +29,7 @@ 'migration/tests/test_dumps/*', 'migration/versions/*', ]}, - message_extractors = { + message_extractors={ 'ckan': [ ('**.py', 'python', None), ('**.js', 'javascript', None), From 1ca945f79f600d6e4521e04cc5b90a75834dce4b Mon Sep 17 00:00:00 2001 From: Samuele Santi Date: Fri, 18 Oct 2013 12:57:29 +0200 Subject: [PATCH 03/13] Entry points converted to dict --- setup.py | 186 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 94 insertions(+), 92 deletions(-) diff --git a/setup.py b/setup.py index 04fc1647fec..c40a746d72b 100644 --- a/setup.py +++ b/setup.py @@ -8,6 +8,99 @@ from ckan import (__version__, __description__, __long_description__, __license__) +entry_points = { + 'nose.plugins.0.10': [ + 'main = ckan.ckan_nose_plugin:CkanNose', + ], + 'paste.app_factory': [ + 'main = ckan.config.middleware:make_app', + ], + 'paste.app_install': [ + 'main = ckan.config.install:CKANInstaller', + ], + 'paste.paster_command': [ + 'db = ckan.lib.cli:ManageDb', + 'create-test-data = ckan.lib.cli:CreateTestDataCommand', + 'sysadmin = ckan.lib.cli:Sysadmin', + 'user = ckan.lib.cli:UserCmd', + 'dataset = ckan.lib.cli:DatasetCmd', + 'search-index = ckan.lib.cli:SearchIndexCommand', + 'ratings = ckan.lib.cli:Ratings', + 'notify = ckan.lib.cli:Notification', + 'celeryd = ckan.lib.cli:Celery', + 'rdf-export = ckan.lib.cli:RDFExport', + 'tracking = ckan.lib.cli:Tracking', + 'plugin-info = ckan.lib.cli:PluginInfo', + 'profile = ckan.lib.cli:Profile', + 'color = ckan.lib.cli:CreateColorSchemeCommand', + 'check-po-files = ckan.i18n.check_po_files:CheckPoFiles', + 'trans = ckan.lib.cli:TranslationsCommand', + 'minify = ckan.lib.cli:MinifyCommand', + 'less = ckan.lib.cli:LessCommand', + 'datastore = ckanext.datastore.commands:SetupDatastoreCommand', + 'front-end-build = ckan.lib.cli:FrontEndBuildCommand', + ], + 'console_scripts': [ + 'ckan-admin = bin.ckan_admin:Command', + ], + 'paste.paster_create_template': [ + 'ckanext = ckan.pastertemplates:CkanextTemplate', + ], + 'ckan.forms': [ + 'standard = ckan.forms.package:get_standard_fieldset', + 'package = ckan.forms.package:get_standard_fieldset', + 'group = ckan.forms.group:get_group_fieldset', + 'package_group = ckan.forms.group:get_package_group_fieldset', + ], + 'ckan.search': [ + 'sql = ckan.lib.search.sql:SqlSearchBackend', + 'solr = ckan.lib.search.solr_backend:SolrSearchBackend', + ], + 'ckan.plugins': [ + 'synchronous_search = ckan.lib.search:SynchronousSearchPlugin', + 'stats = ckanext.stats.plugin:StatsPlugin', + 'publisher_form = ckanext.publisher_form.forms:PublisherForm', + 'publisher_dataset_form = ckanext.publisher_form.forms:PublisherDatasetForm', + 'multilingual_dataset = ckanext.multilingual.plugin:MultilingualDataset', + 'multilingual_group = ckanext.multilingual.plugin:MultilingualGroup', + 'multilingual_tag = ckanext.multilingual.plugin:MultilingualTag', + 'organizations = ckanext.organizations.forms:OrganizationForm', + 'organizations_dataset = ckanext.organizations.forms:OrganizationDatasetForm', + 'datastore = ckanext.datastore.plugin:DatastorePlugin', + 'test_tag_vocab_plugin = ckanext.test_tag_vocab_plugin:MockVocabTagsPlugin', + 'resource_proxy = ckanext.resourceproxy.plugin:ResourceProxy', + 'text_preview = ckanext.textpreview.plugin:TextPreview', + 'pdf_preview = ckanext.pdfpreview.plugin:PdfPreview', + 'recline_preview = ckanext.reclinepreview.plugin:ReclinePreview', + 'example_itemplatehelpers = ckanext.example_itemplatehelpers.plugin:ExampleITemplateHelpersPlugin', + 'example_idatasetform = ckanext.example_idatasetform.plugin:ExampleIDatasetFormPlugin', + 'example_iauthfunctions_v1 = ckanext.example_iauthfunctions.plugin_v1:ExampleIAuthFunctionsPlugin', + 'example_iauthfunctions_v2 = ckanext.example_iauthfunctions.plugin_v2:ExampleIAuthFunctionsPlugin', + 'example_iauthfunctions_v3 = ckanext.example_iauthfunctions.plugin_v3:ExampleIAuthFunctionsPlugin', + 'example_iauthfunctions = ckanext.example_iauthfunctions.plugin:ExampleIAuthFunctionsPlugin', + ], + 'ckan.system_plugins': [ + 'domain_object_mods = ckan.model.modification:DomainObjectModificationExtension', + ], + 'ckan.test_plugins': [ + 'routes_plugin = tests.ckantestplugins:RoutesPlugin', + 'mapper_plugin = tests.ckantestplugins:MapperPlugin', + 'session_plugin = tests.ckantestplugins:SessionPlugin', + 'mapper_plugin2 = tests.ckantestplugins:MapperPlugin2', + 'authorizer_plugin = tests.ckantestplugins:AuthorizerPlugin', + 'test_observer_plugin = tests.ckantestplugins:PluginObserverPlugin', + 'action_plugin = tests.ckantestplugins:ActionPlugin', + 'auth_plugin = tests.ckantestplugins:AuthPlugin', + 'test_group_plugin = tests.ckantestplugins:MockGroupControllerPlugin', + 'test_package_controller_plugin = tests.ckantestplugins:MockPackageControllerPlugin', + 'test_resource_preview = tests.ckantestplugins:MockResourcePreviewExtension', + 'test_json_resource_preview = tests.ckantestplugins:JsonMockResourcePreviewExtension', + ], + 'babel.extractors': [ + 'ckan = ckan.lib.extract:extract_ckan', + ], +} + setup( name='ckan', version=__version__, @@ -56,98 +149,7 @@ }), ] }, - entry_points=""" - [nose.plugins.0.10] - main = ckan.ckan_nose_plugin:CkanNose - - [paste.app_factory] - main = ckan.config.middleware:make_app - - [paste.app_install] - main = ckan.config.install:CKANInstaller - - [paste.paster_command] - db = ckan.lib.cli:ManageDb - create-test-data = ckan.lib.cli:CreateTestDataCommand - sysadmin = ckan.lib.cli:Sysadmin - user = ckan.lib.cli:UserCmd - dataset = ckan.lib.cli:DatasetCmd - search-index = ckan.lib.cli:SearchIndexCommand - ratings = ckan.lib.cli:Ratings - notify = ckan.lib.cli:Notification - celeryd = ckan.lib.cli:Celery - rdf-export = ckan.lib.cli:RDFExport - tracking = ckan.lib.cli:Tracking - plugin-info = ckan.lib.cli:PluginInfo - profile = ckan.lib.cli:Profile - color = ckan.lib.cli:CreateColorSchemeCommand - check-po-files = ckan.i18n.check_po_files:CheckPoFiles - trans = ckan.lib.cli:TranslationsCommand - minify = ckan.lib.cli:MinifyCommand - less = ckan.lib.cli:LessCommand - datastore = ckanext.datastore.commands:SetupDatastoreCommand - front-end-build = ckan.lib.cli:FrontEndBuildCommand - - - [console_scripts] - ckan-admin = bin.ckan_admin:Command - - [paste.paster_create_template] - ckanext=ckan.pastertemplates:CkanextTemplate - - [ckan.forms] - standard = ckan.forms.package:get_standard_fieldset - package = ckan.forms.package:get_standard_fieldset - group = ckan.forms.group:get_group_fieldset - package_group = ckan.forms.group:get_package_group_fieldset - - [ckan.search] - sql = ckan.lib.search.sql:SqlSearchBackend - solr = ckan.lib.search.solr_backend:SolrSearchBackend - - [ckan.plugins] - synchronous_search = ckan.lib.search:SynchronousSearchPlugin - stats=ckanext.stats.plugin:StatsPlugin - publisher_form=ckanext.publisher_form.forms:PublisherForm - publisher_dataset_form=ckanext.publisher_form.forms:PublisherDatasetForm - multilingual_dataset=ckanext.multilingual.plugin:MultilingualDataset - multilingual_group=ckanext.multilingual.plugin:MultilingualGroup - multilingual_tag=ckanext.multilingual.plugin:MultilingualTag - organizations=ckanext.organizations.forms:OrganizationForm - organizations_dataset=ckanext.organizations.forms:OrganizationDatasetForm - datastore=ckanext.datastore.plugin:DatastorePlugin - test_tag_vocab_plugin=ckanext.test_tag_vocab_plugin:MockVocabTagsPlugin - resource_proxy=ckanext.resourceproxy.plugin:ResourceProxy - text_preview=ckanext.textpreview.plugin:TextPreview - pdf_preview=ckanext.pdfpreview.plugin:PdfPreview - recline_preview=ckanext.reclinepreview.plugin:ReclinePreview - example_itemplatehelpers=ckanext.example_itemplatehelpers.plugin:ExampleITemplateHelpersPlugin - example_idatasetform=ckanext.example_idatasetform.plugin:ExampleIDatasetFormPlugin - example_iauthfunctions_v1=ckanext.example_iauthfunctions.plugin_v1:ExampleIAuthFunctionsPlugin - example_iauthfunctions_v2=ckanext.example_iauthfunctions.plugin_v2:ExampleIAuthFunctionsPlugin - example_iauthfunctions_v3=ckanext.example_iauthfunctions.plugin_v3:ExampleIAuthFunctionsPlugin - example_iauthfunctions=ckanext.example_iauthfunctions.plugin:ExampleIAuthFunctionsPlugin - - [ckan.system_plugins] - domain_object_mods = ckan.model.modification:DomainObjectModificationExtension - - [ckan.test_plugins] - routes_plugin=tests.ckantestplugins:RoutesPlugin - mapper_plugin=tests.ckantestplugins:MapperPlugin - session_plugin=tests.ckantestplugins:SessionPlugin - mapper_plugin2=tests.ckantestplugins:MapperPlugin2 - authorizer_plugin=tests.ckantestplugins:AuthorizerPlugin - test_observer_plugin=tests.ckantestplugins:PluginObserverPlugin - action_plugin=tests.ckantestplugins:ActionPlugin - auth_plugin=tests.ckantestplugins:AuthPlugin - test_group_plugin=tests.ckantestplugins:MockGroupControllerPlugin - test_package_controller_plugin=tests.ckantestplugins:MockPackageControllerPlugin - test_resource_preview=tests.ckantestplugins:MockResourcePreviewExtension - test_json_resource_preview=tests.ckantestplugins:JsonMockResourcePreviewExtension - - [babel.extractors] - ckan = ckan.lib.extract:extract_ckan - """, + entry_points=entry_points, # setup.py test command needs a TestSuite so does not work with py.test # test_suite = 'nose.collector', # tests_require=[ 'py >= 0.8.0-alpha2' ] From 4f6e390e03759aa0333e534ef7e9f521725ec8d9 Mon Sep 17 00:00:00 2001 From: Nigel Babu Date: Mon, 21 Oct 2013 13:06:41 +0530 Subject: [PATCH 04/13] Create new schema for related update --- ckan/logic/action/update.py | 2 +- ckan/logic/schema.py | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/ckan/logic/action/update.py b/ckan/logic/action/update.py index 3db2d0d19cf..13fc147b50b 100644 --- a/ckan/logic/action/update.py +++ b/ckan/logic/action/update.py @@ -132,7 +132,7 @@ def related_update(context, data_dict): id = _get_or_bust(data_dict, "id") session = context['session'] - schema = context.get('schema') or schema_.default_related_schema() + schema = context.get('schema') or schema_.default_update_related_schema() related = model.Related.get(id) context["related"] = related diff --git a/ckan/logic/schema.py b/ckan/logic/schema.py index 41e3c724656..9fb859fde65 100644 --- a/ckan/logic/schema.py +++ b/ckan/logic/schema.py @@ -331,6 +331,15 @@ def default_related_schema(): return schema +def default_update_related_schema(): + schema = default_related_schema() + schema['id'] = [not_empty, unicode] + schema['title'] = [ignore_missing, unicode] + schema['type'] = [ignore_missing, unicode] + schema['owner_id'] = [ignore_missing, unicode] + return schema + + def default_extras_schema(): schema = { From 839a0981d2c92e99b3c08707da147d3116008b47 Mon Sep 17 00:00:00 2001 From: Nigel Babu Date: Mon, 21 Oct 2013 15:58:06 +0530 Subject: [PATCH 05/13] Add tests for related actions --- ckan/tests/logic/test_action.py | 61 +++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/ckan/tests/logic/test_action.py b/ckan/tests/logic/test_action.py index ed1907ebdb8..fac25a7ba86 100644 --- a/ckan/tests/logic/test_action.py +++ b/ckan/tests/logic/test_action.py @@ -1978,3 +1978,64 @@ def _assert_we_can_add_user_to_group(self, user_id, group_id): group_ids = [g.id for g in groups] assert res['success'] is True, res assert group.id in group_ids, (group, user_groups) + + +class TestRelatedAction(WsgiAppCase): + + sysadmin_user = None + + normal_user = None + + @classmethod + def setup_class(cls): + search.clear() + CreateTestData.create() + cls.sysadmin_user = model.User.get('testsysadmin') + + @classmethod + def teardown_class(cls): + model.repo.rebuild_db() + + def _add_basic_package(self, package_name=u'test_package', **kwargs): + package = { + 'name': package_name, + 'title': u'A Novel By Tolstoy', + 'resources': [{ + 'description': u'Full text.', + 'format': u'plain text', + 'url': u'http://www.annakarenina.com/download/' + }] + } + package.update(kwargs) + + postparams = '%s=1' % json.dumps(package) + res = self.app.post('/api/action/package_create', params=postparams, + extra_environ={'Authorization': 'tester'}) + return json.loads(res.body)['result'] + + def test_01_update_add_related_item(self): + package = self._add_basic_package() + related_item = { + "description": "Testing a Description", + "url": "http://example.com/image.png", + "title": "Testing", + "featured": 0, + "image_url": "http://example.com/image.png", + "type": "idea", + "dataset_id": package['id'], + } + related_item_json = json.dumps(related_item) + res_create = self.app.post('/api/action/related_create', params=related_item_json, + extra_environ={'Authorization': 'tester'}) + assert res_create.json['success'] == True + + related_update = res_create.json['result'] + related_update = {'id': related_update['id'], 'title': 'Updated'} + related_update_json = json.dumps(related_update) + res_update = self.app.post('/api/action/related_update', params=related_update_json, + extra_environ={'Authorization': 'tester'}) + assert res_update.json['success'] == True + res_update_json = res_update.json['result'] + assert res_update_json['title'] == related_update['title'] + + From 5cc76acca3802922d37db5f341fe72bd4365c60c Mon Sep 17 00:00:00 2001 From: Stefan Oderbolz Date: Mon, 21 Oct 2013 15:26:25 +0200 Subject: [PATCH 06/13] Add organizations to the default facet titles Currently this is only set in the package controller, so on all other pages that display the facets the title is not displayed correctly --- ckan/controllers/group.py | 3 ++- ckan/controllers/home.py | 1 + ckan/lib/helpers.py | 3 ++- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/ckan/controllers/group.py b/ckan/controllers/group.py index 66bd533fd43..06d34496f2e 100644 --- a/ckan/controllers/group.py +++ b/ckan/controllers/group.py @@ -278,7 +278,8 @@ def pager_url(q=None, page=None): facets = OrderedDict() - default_facet_titles = {'groups': _('Groups'), + default_facet_titles = {'organization': _('Organizations'), + 'groups': _('Groups'), 'tags': _('Tags'), 'res_format': _('Formats'), 'license_id': _('License')} diff --git a/ckan/controllers/home.py b/ckan/controllers/home.py index da3d4b3901b..7aa15be87bd 100644 --- a/ckan/controllers/home.py +++ b/ckan/controllers/home.py @@ -67,6 +67,7 @@ def index(self): c.search_facets = query['search_facets'] c.facet_titles = { + 'organization': _('Organizations'), 'groups': _('Groups'), 'tags': _('Tags'), 'res_format': _('Formats'), diff --git a/ckan/lib/helpers.py b/ckan/lib/helpers.py index edd9746f0a8..9a2b83ddfb1 100644 --- a/ckan/lib/helpers.py +++ b/ckan/lib/helpers.py @@ -597,7 +597,8 @@ def get_facet_title(name): if config_title: return config_title - facet_titles = {'groups': _('Groups'), + facet_titles = {'organization': _('Organizations'), + 'groups': _('Groups'), 'tags': _('Tags'), 'res_format': _('Formats'), 'license': _('License'), } From 48f5eeb6cda7955bc89aac50ad27969bd5abfe04 Mon Sep 17 00:00:00 2001 From: Ian Ward Date: Mon, 21 Oct 2013 14:57:23 -0400 Subject: [PATCH 07/13] [#1281] DefaultOrganizationForm instead of hard-coded values in controller --- ckan/controllers/organization.py | 41 -------------------------------- ckan/lib/plugins.py | 39 +++++++++++++++++++++++++++++- 2 files changed, 38 insertions(+), 42 deletions(-) diff --git a/ckan/controllers/organization.py b/ckan/controllers/organization.py index b44d95e057f..3907143a187 100644 --- a/ckan/controllers/organization.py +++ b/ckan/controllers/organization.py @@ -15,46 +15,5 @@ class OrganizationController(group.GroupController): # this makes us use organization actions group_type = 'organization' - def _group_form(self, group_type=None): - return 'organization/new_organization_form.html' - - def _form_to_db_schema(self, group_type=None): - return group.lookup_group_plugin(group_type).form_to_db_schema() - - def _db_to_form_schema(self, group_type=None): - '''This is an interface to manipulate data from the database - into a format suitable for the form (optional)''' - pass - - def _setup_template_variables(self, context, data_dict, group_type=None): - pass - - def _new_template(self, group_type): - return 'organization/new.html' - - def _about_template(self, group_type): - return 'organization/about.html' - - def _index_template(self, group_type): - return 'organization/index.html' - - def _admins_template(self, group_type): - return 'organization/admins.html' - - def _bulk_process_template(self, group_type): - return 'organization/bulk_process.html' - - def _read_template(self, group_type): - return 'organization/read.html' - - def _history_template(self, group_type): - return group.lookup_group_plugin(group_type).history_template() - - def _edit_template(self, group_type): - return 'organization/edit.html' - - def _activity_template(self, group_type): - return 'organization/activity_stream.html' - def _guess_group_type(self, expecting_name=False): return 'organization' diff --git a/ckan/lib/plugins.py b/ckan/lib/plugins.py index 97263dcf7f8..40a398bd3f4 100644 --- a/ckan/lib/plugins.py +++ b/ckan/lib/plugins.py @@ -53,7 +53,8 @@ def lookup_group_plugin(group_type=None): """ if group_type is None: return _default_group_plugin - return _group_plugins.get(group_type, _default_group_plugin) + return _group_plugins.get(group_type, _default_organization_plugin + if group_type == 'organization' else _default_group_plugin) def register_package_plugins(map): @@ -418,3 +419,39 @@ def setup_template_variables(self, context, data_dict): c.auth_for_change_state = True except logic.NotAuthorized: c.auth_for_change_state = False + + +class DefaultOrganizationForm(DefaultGroupForm): + def group_form(self): + return 'organization/new_organization_form.html' + + def setup_template_variables(self, context, data_dict): + pass + + def new_template(self): + return 'organization/new.html' + + def about_template(self): + return 'organization/about.html' + + def index_template(self): + return 'organization/index.html' + + def admins_template(self): + return 'organization/admins.html' + + def bulk_process_template(self): + return 'organization/bulk_process.html' + + def read_template(self): + return 'organization/read.html' + + # don't override history_template - use group template for history + + def edit_template(self): + return 'organization/edit.html' + + def activity_template(self): + return 'organization/activity_stream.html' + +_default_organization_plugin = DefaultOrganizationForm() From d30986d9f585e5897992ed97146e04672c14d54e Mon Sep 17 00:00:00 2001 From: Stefan Oderbolz Date: Wed, 9 Oct 2013 18:48:12 +0200 Subject: [PATCH 08/13] Added IOrganizationController to MultilingualGroup This ensures that organizations are being translated just like groups --- ckanext/multilingual/plugin.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ckanext/multilingual/plugin.py b/ckanext/multilingual/plugin.py index a554042f209..a4ee31e3b48 100644 --- a/ckanext/multilingual/plugin.py +++ b/ckanext/multilingual/plugin.py @@ -1,7 +1,7 @@ import sets import ckan from ckan.plugins import SingletonPlugin, implements, IPackageController -from ckan.plugins import IGroupController, ITagController +from ckan.plugins import IGroupController, IOrganizationController, ITagController import pylons import ckan.logic.action.get as action_get from pylons import config @@ -253,6 +253,7 @@ class MultilingualGroup(SingletonPlugin): ''' implements(IGroupController, inherit=True) + implements(IOrganizationController, inherit=True) def before_view(self, data_dict): translated_data_dict = translate_data_dict(data_dict) From 904dbf045f47f26692d467edca2ab1a6133e5e60 Mon Sep 17 00:00:00 2001 From: John Glover Date: Wed, 23 Oct 2013 15:24:45 +0200 Subject: [PATCH 09/13] [#1274] PEP8 --- ckan/tests/test_coding_standards.py | 1 - .../tests/test_multilingual_plugin.py | 271 +++++++++--------- 2 files changed, 134 insertions(+), 138 deletions(-) diff --git a/ckan/tests/test_coding_standards.py b/ckan/tests/test_coding_standards.py index f0b7469c3f4..349f4785f6a 100644 --- a/ckan/tests/test_coding_standards.py +++ b/ckan/tests/test_coding_standards.py @@ -828,7 +828,6 @@ class TestPep8(object): 'ckanext/example_idatasetform/plugin.py', 'ckanext/example_itemplatehelpers/plugin.py', 'ckanext/multilingual/plugin.py', - 'ckanext/multilingual/tests/test_multilingual_plugin.py', 'ckanext/reclinepreview/plugin.py', 'ckanext/reclinepreview/tests/test_preview.py', 'ckanext/resourceproxy/plugin.py', diff --git a/ckanext/multilingual/tests/test_multilingual_plugin.py b/ckanext/multilingual/tests/test_multilingual_plugin.py index ecc22b745f7..d7c4ec8a7f0 100644 --- a/ckanext/multilingual/tests/test_multilingual_plugin.py +++ b/ckanext/multilingual/tests/test_multilingual_plugin.py @@ -9,10 +9,11 @@ import paste.fixture import pylons.test -class TestDatasetTermTranslation(ckan.tests.html_check.HtmlCheckMethods): - '''Test the translation of datasets by the multilingual_dataset plugin. +_create_test_data = ckan.lib.create_test_data + - ''' +class TestDatasetTermTranslation(ckan.tests.html_check.HtmlCheckMethods): + 'Test the translation of datasets by the multilingual_dataset plugin.' @classmethod def setup(cls): cls.app = paste.fixture.TestApp(pylons.test.pylonsapp) @@ -20,24 +21,20 @@ def setup(cls): ckan.plugins.load('multilingual_group') ckan.plugins.load('multilingual_tag') ckan.tests.setup_test_search_index() - ckan.lib.create_test_data.CreateTestData.create_translations_test_data() + _create_test_data.CreateTestData.create_translations_test_data() # Add translation terms that match a couple of group names and package # names. Group names and package names should _not_ get translated even # if there are terms matching them, because they are used to form URLs. for term in ('roger', 'david', 'annakarenina', 'warandpeace'): for lang_code in ('en', 'de', 'fr'): - data_dict = { - 'term': term, - 'term_translation': 'this should not be rendered', - 'lang_code': lang_code, - } - context = { - 'model': ckan.model, - 'session': ckan.model.Session, - 'user': 'testsysadmin', - } - ckan.logic.action.update.term_translation_update(context, - data_dict) + data_dict = {'term': term, + 'term_translation': 'this should not be rendered', + 'lang_code': lang_code} + context = {'model': ckan.model, + 'session': ckan.model.Session, + 'user': 'testsysadmin'} + ckan.logic.action.update.term_translation_update( + context, data_dict) @classmethod def teardown(cls): @@ -54,34 +51,34 @@ def test_dataset_read_translation(self): ''' # Fetch the dataset view page for a number of different languages and # test for the presence of translated and not translated terms. - offset = routes.url_for(controller='package', action='read', - id='annakarenina') + offset = routes.url_for( + controller='package', action='read', id='annakarenina') for (lang_code, translations) in ( - ('de', ckan.lib.create_test_data.german_translations), - ('fr', ckan.lib.create_test_data.french_translations), - ('en', ckan.lib.create_test_data.english_translations), + ('de', _create_test_data.german_translations), + ('fr', _create_test_data.french_translations), + ('en', _create_test_data.english_translations), ('pl', {})): response = self.app.get(offset, status=200, - extra_environ={'CKAN_LANG': lang_code, - 'CKAN_CURRENT_URL': offset}) + extra_environ={'CKAN_LANG': lang_code, + 'CKAN_CURRENT_URL': offset}) terms = ('A Novel By Tolstoy', - 'Index of the novel', - 'russian', - 'tolstoy', - "Dave's books", - "Roger's books", - 'romantic novel', - 'book', - '123', - '456', - '789', - 'plain text', - ) + 'Index of the novel', + 'russian', + 'tolstoy', + "Dave's books", + "Roger's books", + 'romantic novel', + 'book', + '123', + '456', + '789', + 'plain text',) for term in terms: if term in translations: assert translations[term] in response - elif term in ckan.lib.create_test_data.english_translations: - assert ckan.lib.create_test_data.english_translations[term] in response + elif term in _create_test_data.english_translations: + assert (_create_test_data.english_translations[term] + in response) else: assert term in response for tag_name in ('123', '456', '789', 'russian', 'tolstoy'): @@ -96,23 +93,25 @@ def test_tag_read_translation(self): ''' for tag_name in ('123', '456', '789', 'russian', 'tolstoy'): - offset = routes.url_for(controller='tag', action='read', - id=tag_name) + offset = routes.url_for( + controller='tag', action='read', id=tag_name) for (lang_code, translations) in ( - ('de', ckan.lib.create_test_data.german_translations), - ('fr', ckan.lib.create_test_data.french_translations), - ('en', ckan.lib.create_test_data.english_translations), + ('de', _create_test_data.german_translations), + ('fr', _create_test_data.french_translations), + ('en', _create_test_data.english_translations), ('pl', {})): - response = self.app.get(offset, status=200, - extra_environ={'CKAN_LANG': lang_code, - 'CKAN_CURRENT_URL': offset}) + response = self.app.get( + offset, + status=200, + extra_environ={'CKAN_LANG': lang_code, + 'CKAN_CURRENT_URL': offset}) terms = ('A Novel By Tolstoy', tag_name, 'plain text', 'json') for term in terms: if term in translations: assert translations[term] in response - elif term in ( - ckan.lib.create_test_data.english_translations): - assert ckan.lib.create_test_data.english_translations[term] in response + elif term in _create_test_data.english_translations: + assert (_create_test_data.english_translations[term] + in response) else: assert term in response assert 'this should not be rendered' not in response @@ -123,55 +122,53 @@ def test_user_read_translation(self): ''' for user_name in ('annafan',): - offset = routes.url_for(controller='user', action='read', - id=user_name) + offset = routes.url_for( + controller='user', action='read', id=user_name) for (lang_code, translations) in ( - ('de', ckan.lib.create_test_data.german_translations), - ('fr', ckan.lib.create_test_data.french_translations), - ('en', ckan.lib.create_test_data.english_translations), + ('de', _create_test_data.german_translations), + ('fr', _create_test_data.french_translations), + ('en', _create_test_data.english_translations), ('pl', {})): - response = self.app.get(offset, status=200, - extra_environ={'CKAN_LANG': lang_code, - 'CKAN_CURRENT_URL': offset}) + response = self.app.get( + offset, + status=200, + extra_environ={'CKAN_LANG': lang_code, + 'CKAN_CURRENT_URL': offset}) terms = ('A Novel By Tolstoy', 'plain text', 'json') for term in terms: if term in translations: assert translations[term] in response - elif term in ( - ckan.lib.create_test_data.english_translations): - assert ckan.lib.create_test_data.english_translations[term] in response + elif term in _create_test_data.english_translations: + assert (_create_test_data.english_translations[term] + in response) else: assert term in response assert 'this should not be rendered' not in response def test_group_read_translation(self): for (lang_code, translations) in ( - ('de', ckan.lib.create_test_data.german_translations), - ('fr', ckan.lib.create_test_data.french_translations), - ('en', ckan.lib.create_test_data.english_translations), + ('de', _create_test_data.german_translations), + ('fr', _create_test_data.french_translations), + ('en', _create_test_data.english_translations), ('pl', {})): offset = '/%s/group/roger' % lang_code response = self.app.get(offset, status=200) terms = ('A Novel By Tolstoy', - 'Index of the novel', - 'russian', - 'tolstoy', - #"Dave's books", - "Roger's books", - #'Other (Open)', - #'romantic novel', - #'book', - '123', - '456', - '789', - 'plain text', - 'Roger likes these books.', - ) + 'Index of the novel', + 'russian', + 'tolstoy', + "Roger's books", + '123', + '456', + '789', + 'plain text', + 'Roger likes these books.',) for term in terms: if term in translations: assert translations[term] in response - elif term in ckan.lib.create_test_data.english_translations: - assert ckan.lib.create_test_data.english_translations[term] in response + elif term in _create_test_data.english_translations: + assert (_create_test_data.english_translations[term] + in response) else: assert term in response for tag_name in ('123', '456', '789', 'russian', 'tolstoy'): @@ -180,31 +177,34 @@ def test_group_read_translation(self): def test_dataset_index_translation(self): for (lang_code, translations) in ( - ('de', ckan.lib.create_test_data.german_translations), - ('fr', ckan.lib.create_test_data.french_translations), - ('en', ckan.lib.create_test_data.english_translations), + ('de', _create_test_data.german_translations), + ('fr', _create_test_data.french_translations), + ('en', _create_test_data.english_translations), ('pl', {})): offset = '/%s/dataset' % lang_code response = self.app.get(offset, status=200) for term in ('Index of the novel', 'russian', 'tolstoy', - "Dave's books", "Roger's books", 'plain text'): + "Dave's books", "Roger's books", 'plain text'): if term in translations: assert translations[term] in response - elif term in ckan.lib.create_test_data.english_translations: - assert ckan.lib.create_test_data.english_translations[term] in response + elif term in _create_test_data.english_translations: + assert (_create_test_data.english_translations[term] + in response) else: assert term in response for tag_name in ('123', '456', '789', 'russian', 'tolstoy'): - assert '/%s/dataset?tags=%s' % (lang_code, tag_name) in response + assert ('/%s/dataset?tags=%s' % (lang_code, tag_name) + in response) for group_name in ('david', 'roger'): - assert '/%s/dataset?groups=%s' % (lang_code, group_name) in response + assert ('/%s/dataset?groups=%s' % (lang_code, group_name) + in response) assert 'this should not be rendered' not in response def test_group_index_translation(self): for (lang_code, translations) in ( - ('de', ckan.lib.create_test_data.german_translations), - ('fr', ckan.lib.create_test_data.french_translations), - ('en', ckan.lib.create_test_data.english_translations), + ('de', _create_test_data.german_translations), + ('fr', _create_test_data.french_translations), + ('en', _create_test_data.english_translations), ('pl', {})): offset = '/%s/group' % lang_code response = self.app.get(offset, status=200) @@ -217,8 +217,9 @@ def test_group_index_translation(self): for term in terms: if term in translations: assert translations[term] in response - elif term in ckan.lib.create_test_data.english_translations: - assert ckan.lib.create_test_data.english_translations[term] in response + elif term in _create_test_data.english_translations: + assert (_create_test_data.english_translations[term] + in response) else: assert term in response for group_name in ('david', 'roger'): @@ -227,9 +228,9 @@ def test_group_index_translation(self): def test_tag_index_translation(self): for (lang_code, translations) in ( - ('de', ckan.lib.create_test_data.german_translations), - ('fr', ckan.lib.create_test_data.french_translations), - ('en', ckan.lib.create_test_data.english_translations), + ('de', _create_test_data.german_translations), + ('fr', _create_test_data.french_translations), + ('en', _create_test_data.english_translations), ('pl', {})): offset = '/%s/tag' % lang_code response = self.app.get(offset, status=200) @@ -243,13 +244,15 @@ def test_tag_index_translation(self): for term in terms: if term in translations: assert translations[term] in response - elif term in ckan.lib.create_test_data.english_translations: - assert ckan.lib.create_test_data.english_translations[term] in response + elif term in _create_test_data.english_translations: + assert (_create_test_data.english_translations[term] + in response) else: assert term in response assert '/%s/tag/%s' % (lang_code, term) in response assert 'this should not be rendered' not in response + class TestDatasetSearchIndex(): @classmethod @@ -260,36 +263,28 @@ def setup_class(cls): data_dicts = [ {'term': 'moo', 'term_translation': 'french_moo', - 'lang_code': 'fr', - }, # + 'lang_code': 'fr'}, {'term': 'moo', 'term_translation': 'this should not be rendered', - 'lang_code': 'fsdas', - }, + 'lang_code': 'fsdas'}, {'term': 'an interesting note', 'term_translation': 'french note', - 'lang_code': 'fr', - }, + 'lang_code': 'fr'}, {'term': 'moon', 'term_translation': 'french moon', - 'lang_code': 'fr', - }, + 'lang_code': 'fr'}, {'term': 'boon', 'term_translation': 'french boon', - 'lang_code': 'fr', - }, + 'lang_code': 'fr'}, {'term': 'boon', 'term_translation': 'italian boon', - 'lang_code': 'it', - }, + 'lang_code': 'it'}, {'term': 'david', 'term_translation': 'french david', - 'lang_code': 'fr', - }, + 'lang_code': 'fr'}, {'term': 'david', 'term_translation': 'italian david', - 'lang_code': 'it', - }, + 'lang_code': 'it'} ] context = { @@ -299,39 +294,41 @@ def setup_class(cls): 'ignore_auth': True, } for data_dict in data_dicts: - ckan.logic.action.update.term_translation_update(context, - data_dict) + ckan.logic.action.update.term_translation_update( + context, data_dict) @classmethod def teardown(cls): ckan.plugins.unload('multilingual_dataset') ckan.plugins.unload('multilingual_group') - def test_translate_terms(self): sample_index_data = { - 'download_url': u'moo', - 'notes': u'an interesting note', - 'tags': [u'moon', 'boon'], - 'title': u'david', - } + 'download_url': u'moo', + 'notes': u'an interesting note', + 'tags': [u'moon', 'boon'], + 'title': u'david', + } - result = mulilingual_plugin.MultilingualDataset().before_index(sample_index_data) + result = mulilingual_plugin.MultilingualDataset().before_index( + sample_index_data) - assert result == {'text_pl': '', - 'text_de': '', - 'text_ro': '', - 'title': u'david', - 'notes': u'an interesting note', - 'tags': [u'moon', 'boon'], - 'title_en': u'david', - 'download_url': u'moo', - 'text_it': u'italian boon', - 'text_es': '', - 'text_en': u'an interesting note moon boon moo', - 'text_nl': '', - 'title_it': u'italian david', - 'text_pt': '', - 'title_fr': u'french david', - 'text_fr': u'french note french boon french_moo french moon'}, result + assert result == { + 'text_pl': '', + 'text_de': '', + 'text_ro': '', + 'title': u'david', + 'notes': u'an interesting note', + 'tags': [u'moon', 'boon'], + 'title_en': u'david', + 'download_url': u'moo', + 'text_it': u'italian boon', + 'text_es': '', + 'text_en': u'an interesting note moon boon moo', + 'text_nl': '', + 'title_it': u'italian david', + 'text_pt': '', + 'title_fr': u'french david', + 'text_fr': u'french note french boon french_moo french moon' + }, result From 05c27cefca4983d387ca1e66d0c381b9b9cbabfe Mon Sep 17 00:00:00 2001 From: Ian Ward Date: Wed, 23 Oct 2013 12:43:47 -0400 Subject: [PATCH 10/13] [#1281] call setup_template_variables in group/org read, about and bulk_process --- ckan/controllers/group.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ckan/controllers/group.py b/ckan/controllers/group.py index 66bd533fd43..f7ee98bef54 100644 --- a/ckan/controllers/group.py +++ b/ckan/controllers/group.py @@ -344,6 +344,9 @@ def pager_url(q=None, page=None): c.facets = {} c.page = h.Page(collection=[]) + self._setup_template_variables(context, {'id':id}, + group_type=group_type) + def bulk_process(self, id): ''' Allow bulk processing of datasets for an organization. Make private/public or delete. For organization admins.''' @@ -828,7 +831,9 @@ def admins(self, id): def about(self, id): c.group_dict = self._get_group_dict(id) - return render(self._about_template(c.group_dict['type'])) + group_type = c.group_dict['type'] + self._setup_template_variables({}, {'id': id}, group_type=group_type) + return render(self._about_template(group_type)) def _get_group_dict(self, id): ''' returns the result of group_show action or aborts if there is a From 3be621a30f55aabb414abeadcf31c7b3141ca067 Mon Sep 17 00:00:00 2001 From: John Glover Date: Thu, 24 Oct 2013 10:37:55 +0200 Subject: [PATCH 11/13] [#1274] Add tests for organization translation --- .../tests/test_multilingual_plugin.py | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/ckanext/multilingual/tests/test_multilingual_plugin.py b/ckanext/multilingual/tests/test_multilingual_plugin.py index d7c4ec8a7f0..88041b54d59 100644 --- a/ckanext/multilingual/tests/test_multilingual_plugin.py +++ b/ckanext/multilingual/tests/test_multilingual_plugin.py @@ -3,6 +3,7 @@ import ckan.lib.helpers import ckan.lib.create_test_data import ckan.logic.action.update +import ckan.model as model import ckan.tests import ckan.tests.html_check import routes @@ -22,6 +23,21 @@ def setup(cls): ckan.plugins.load('multilingual_tag') ckan.tests.setup_test_search_index() _create_test_data.CreateTestData.create_translations_test_data() + + cls.sysadmin_user = model.User.get('testsysadmin') + cls.org = {'name': 'test_org', + 'title': 'russian', + 'description': 'Roger likes these books.'} + ckan.tests.call_action_api(cls.app, 'organization_create', + apikey=cls.sysadmin_user.apikey, + **cls.org) + dataset = {'name': 'test_org_dataset', + 'title': 'A Novel By Tolstoy', + 'owner_org': cls.org['name']} + ckan.tests.call_action_api(cls.app, 'package_create', + apikey=cls.sysadmin_user.apikey, + **dataset) + # Add translation terms that match a couple of group names and package # names. Group names and package names should _not_ get translated even # if there are terms matching them, because they are used to form URLs. @@ -175,6 +191,28 @@ def test_group_read_translation(self): assert '%s?tags=%s' % (offset, tag_name) in response assert 'this should not be rendered' not in response + def test_org_read_translation(self): + for (lang_code, translations) in ( + ('de', _create_test_data.german_translations), + ('fr', _create_test_data.french_translations), + ('en', _create_test_data.english_translations), + ('pl', {})): + offset = '/{0}/organization/{1}'.format( + lang_code, self.org['name']) + response = self.app.get(offset, status=200) + terms = ('A Novel By Tolstoy', + 'russian', + 'Roger likes these books.') + for term in terms: + if term in translations: + assert translations[term] in response + elif term in _create_test_data.english_translations: + assert (_create_test_data.english_translations[term] + in response) + else: + assert term in response + assert 'this should not be rendered' not in response + def test_dataset_index_translation(self): for (lang_code, translations) in ( ('de', _create_test_data.german_translations), @@ -226,6 +264,26 @@ def test_group_index_translation(self): assert '/%s/group/%s' % (lang_code, group_name) in response assert 'this should not be rendered' not in response + def test_org_index_translation(self): + for (lang_code, translations) in ( + ('de', _create_test_data.german_translations), + ('fr', _create_test_data.french_translations), + ('en', _create_test_data.english_translations), + ('pl', {})): + offset = '/{0}/organization'.format(lang_code) + response = self.app.get(offset, status=200) + for term in ('russian', 'Roger likes these books.'): + if term in translations: + assert translations[term] in response + elif term in _create_test_data.english_translations: + assert (_create_test_data.english_translations[term] + in response) + else: + assert term in response, response + assert ('/{0}/organization/{1}'.format(lang_code, self.org['name']) + in response) + assert 'this should not be rendered' not in response + def test_tag_index_translation(self): for (lang_code, translations) in ( ('de', _create_test_data.german_translations), From 58ccf52ee94c1650944f2481e4ab91a829f3a07a Mon Sep 17 00:00:00 2001 From: John Glover Date: Thu, 24 Oct 2013 12:27:28 +0200 Subject: [PATCH 12/13] [#504] PEP8, and verify that items in original related_item dict are still present after the partial update. --- ckan/tests/logic/test_action.py | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/ckan/tests/logic/test_action.py b/ckan/tests/logic/test_action.py index fac25a7ba86..c295d9271ae 100644 --- a/ckan/tests/logic/test_action.py +++ b/ckan/tests/logic/test_action.py @@ -2013,7 +2013,7 @@ def _add_basic_package(self, package_name=u'test_package', **kwargs): extra_environ={'Authorization': 'tester'}) return json.loads(res.body)['result'] - def test_01_update_add_related_item(self): + def test_update_add_related_item(self): package = self._add_basic_package() related_item = { "description": "Testing a Description", @@ -2025,17 +2025,22 @@ def test_01_update_add_related_item(self): "dataset_id": package['id'], } related_item_json = json.dumps(related_item) - res_create = self.app.post('/api/action/related_create', params=related_item_json, - extra_environ={'Authorization': 'tester'}) - assert res_create.json['success'] == True + res_create = self.app.post('/api/action/related_create', + params=related_item_json, + extra_environ={'Authorization': 'tester'}) + assert res_create.json['success'] related_update = res_create.json['result'] related_update = {'id': related_update['id'], 'title': 'Updated'} related_update_json = json.dumps(related_update) - res_update = self.app.post('/api/action/related_update', params=related_update_json, - extra_environ={'Authorization': 'tester'}) - assert res_update.json['success'] == True + res_update = self.app.post('/api/action/related_update', + params=related_update_json, + extra_environ={'Authorization': 'tester'}) + assert res_update.json['success'] res_update_json = res_update.json['result'] assert res_update_json['title'] == related_update['title'] - + related_item.pop('title') + related_item.pop('dataset_id') + for field in related_item: + assert related_item[field] == res_update_json[field] From c22b09089682ed547e53b9f7710ff93502d1fcbe Mon Sep 17 00:00:00 2001 From: amercader Date: Fri, 25 Oct 2013 13:20:08 +0100 Subject: [PATCH 13/13] [#1295] Don't return private datasets on package_list --- ckan/logic/action/get.py | 7 +++++-- ckan/tests/logic/test_action.py | 30 ++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/ckan/logic/action/get.py b/ckan/logic/action/get.py index 70326e75317..ca46ac2ff57 100644 --- a/ckan/logic/action/get.py +++ b/ckan/logic/action/get.py @@ -91,8 +91,11 @@ def package_list(context, data_dict): col = (package_revision_table.c.id if api == 2 else package_revision_table.c.name) query = _select([col]) - query = query.where(_and_(package_revision_table.c.state=='active', - package_revision_table.c.current==True)) + query = query.where(_and_( + package_revision_table.c.state=='active', + package_revision_table.c.current==True, + package_revision_table.c.private==False, + )) query = query.order_by(col) limit = data_dict.get('limit') diff --git a/ckan/tests/logic/test_action.py b/ckan/tests/logic/test_action.py index d7c37b98aa7..40b1a42d85d 100644 --- a/ckan/tests/logic/test_action.py +++ b/ckan/tests/logic/test_action.py @@ -84,6 +84,36 @@ def test_01_package_list(self): assert 'warandpeace' in res['result'] assert 'annakarenina' in res['result'] + def test_01_package_list_private(self): + tests.call_action_api(self.app, 'organization_create', + name='test_org_2', + apikey=self.sysadmin_user.apikey) + + tests.call_action_api(self.app, 'package_create', + name='public_dataset', + owner_org='test_org_2', + apikey=self.sysadmin_user.apikey) + + res = tests.call_action_api(self.app, 'package_list') + + assert len(res) == 3 + assert 'warandpeace' in res + assert 'annakarenina' in res + assert 'public_dataset' in res + + tests.call_action_api(self.app, 'package_create', + name='private_dataset', + owner_org='test_org_2', + private=True, + apikey=self.sysadmin_user.apikey) + + res = tests.call_action_api(self.app, 'package_list') + assert len(res) == 3 + assert 'warandpeace' in res + assert 'annakarenina' in res + assert 'public_dataset' in res + assert not 'private_dataset' in res + def test_01_current_package_list_with_resources(self): url = '/api/action/current_package_list_with_resources'