From aec31458f41048fdbe32d600833184375bb3c62a Mon Sep 17 00:00:00 2001 From: amercader Date: Wed, 21 Jun 2017 10:47:25 +0100 Subject: [PATCH 01/35] Update version number for 2.4.8b --- ckan/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ckan/__init__.py b/ckan/__init__.py index 31137a9bcc6..a7fe7a81c97 100644 --- a/ckan/__init__.py +++ b/ckan/__init__.py @@ -1,4 +1,4 @@ -__version__ = '2.4.7' +__version__ = '2.4.8b' __description__ = 'CKAN Software' __long_description__ = \ From c08b0c538295cd5c2f67f02297eccd91d0164f87 Mon Sep 17 00:00:00 2001 From: Yan Date: Sun, 26 Feb 2017 21:37:39 +0200 Subject: [PATCH 02/35] [#3457]Create new resource view if resource format changed --- ckan/logic/action/update.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/ckan/logic/action/update.py b/ckan/logic/action/update.py index 4902530850f..d852c4caacf 100644 --- a/ckan/logic/action/update.py +++ b/ckan/logic/action/update.py @@ -124,6 +124,7 @@ def resource_update(context, data_dict): model = context['model'] user = context['user'] id = _get_or_bust(data_dict, "id") + old_resource = _get_action('resource_show')(context, {'id': id}) resource = model.Resource.get(id) context["resource"] = resource @@ -166,6 +167,19 @@ def resource_update(context, data_dict): resource = _get_action('resource_show')(context, {'id': id}) + if old_resource['format'] != resource['format']: + q = model.Session.query(model.ResourceView) \ + .filter(model.ResourceView.resource_id == resource['id']) + resources_view_id = q.all() + if resources_view_id: + for view_id in resources_view_id: + _get_action( + 'resource_view_delete')(context, {'id': view_id.id}) + _get_action('package_create_default_resource_views')( + {'model': context['model'], 'user': context['user'], + 'ignore_auth': True}, + {'package': updated_pkg_dict}) + for plugin in plugins.PluginImplementations(plugins.IResourceController): plugin.after_update(context, resource) From 3f0003e837940c382f63964d02e81b8c8aed125a Mon Sep 17 00:00:00 2001 From: Yan Date: Mon, 22 May 2017 15:36:23 +0300 Subject: [PATCH 03/35] Added test and modification to logic --- ckan/logic/action/update.py | 7 -- ckan/tests/logic/action/test_update.py | 96 ++++++++++++++++++++++++++ 2 files changed, 96 insertions(+), 7 deletions(-) diff --git a/ckan/logic/action/update.py b/ckan/logic/action/update.py index d852c4caacf..546a71af938 100644 --- a/ckan/logic/action/update.py +++ b/ckan/logic/action/update.py @@ -168,13 +168,6 @@ def resource_update(context, data_dict): resource = _get_action('resource_show')(context, {'id': id}) if old_resource['format'] != resource['format']: - q = model.Session.query(model.ResourceView) \ - .filter(model.ResourceView.resource_id == resource['id']) - resources_view_id = q.all() - if resources_view_id: - for view_id in resources_view_id: - _get_action( - 'resource_view_delete')(context, {'id': view_id.id}) _get_action('package_create_default_resource_views')( {'model': context['model'], 'user': context['user'], 'ignore_auth': True}, diff --git a/ckan/tests/logic/action/test_update.py b/ckan/tests/logic/action/test_update.py index 0454d310946..a8fc30cbef5 100644 --- a/ckan/tests/logic/action/test_update.py +++ b/ckan/tests/logic/action/test_update.py @@ -723,6 +723,102 @@ def test_extra_gets_deleted_on_extra_only_update(self): assert_equals(res_returned['anotherfield'], 'second') assert 'newfield' not in res_returned + def test_resource_format_update(self): + dataset = factories.Dataset() + + # Create resource without format + resource = factories.Resource(package=dataset, + url='http://localhost', + name='Test') + res_views = helpers.call_action( + 'resource_view_list', + id=resource['id']) + + assert_equals(len(res_views), 0) + + # Update resource with format + resource = helpers.call_action( + 'resource_update', + id=resource['id'], + format='CSV') + + # Format changed + assert_equals(resource['format'], 'CSV') + + res_views = helpers.call_action( + 'resource_view_list', + id=resource['id']) + + # View for resource is created + assert_equals(len(res_views), 1) + + second_resource = factories.Resource( + package=dataset, + url='http://localhost', + name='Test2', + format='CSV') + + res_views = helpers.call_action( + 'resource_view_list', + id=second_resource['id']) + + assert_equals(len(res_views), 1) + + second_resource = helpers.call_action( + 'resource_update', + id=second_resource['id'], + format='PNG') + + # Format changed + assert_equals(second_resource['format'], 'PNG') + + res_views = helpers.call_action( + 'resource_view_list', + id=second_resource['id']) + + assert_equals(len(res_views), 2) + + third_resource = factories.Resource( + package=dataset, + url='http://localhost', + name='Test2') + + res_views = helpers.call_action( + 'resource_view_list', + id=third_resource['id']) + + assert_equals(len(res_views), 0) + + third_resource = helpers.call_action( + 'resource_update', + id=third_resource['id'], + format='Test format') + + # Format added + assert_equals(third_resource['format'], 'Test format') + + res_views = helpers.call_action( + 'resource_view_list', + id=third_resource['id']) + + # No view created, cause no such format + assert_equals(len(res_views), 0) + + third_resource = helpers.call_action( + 'resource_update', + id=third_resource['id'], + format='CSV') + + # Format changed + assert_equals(third_resource['format'], 'CSV') + + res_views = helpers.call_action( + 'resource_view_list', + id=third_resource['id']) + + # View is created + assert_equals(len(res_views), 1) + class TestConfigOptionUpdate(object): From b74d224ff8b5eb85a96eb3d8249be30e87cb1628 Mon Sep 17 00:00:00 2001 From: Yan Date: Mon, 22 May 2017 17:49:31 +0300 Subject: [PATCH 04/35] Added logic fix and test fix --- ckan/logic/action/update.py | 9 +++++---- ckan/tests/logic/action/test_update.py | 10 ++++++++++ 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/ckan/logic/action/update.py b/ckan/logic/action/update.py index 546a71af938..3e2929d0adf 100644 --- a/ckan/logic/action/update.py +++ b/ckan/logic/action/update.py @@ -124,10 +124,10 @@ def resource_update(context, data_dict): model = context['model'] user = context['user'] id = _get_or_bust(data_dict, "id") - old_resource = _get_action('resource_show')(context, {'id': id}) resource = model.Resource.get(id) context["resource"] = resource + old_resource_format = resource.format if not resource: log.error('Could not find resource ' + id) @@ -167,11 +167,12 @@ def resource_update(context, data_dict): resource = _get_action('resource_show')(context, {'id': id}) - if old_resource['format'] != resource['format']: - _get_action('package_create_default_resource_views')( + if old_resource_format != resource['format']: + _get_action('resource_create_default_resource_views')( {'model': context['model'], 'user': context['user'], 'ignore_auth': True}, - {'package': updated_pkg_dict}) + {'package': updated_pkg_dict, + 'resource': resource}) for plugin in plugins.PluginImplementations(plugins.IResourceController): plugin.after_update(context, resource) diff --git a/ckan/tests/logic/action/test_update.py b/ckan/tests/logic/action/test_update.py index a8fc30cbef5..ad1bf22617f 100644 --- a/ckan/tests/logic/action/test_update.py +++ b/ckan/tests/logic/action/test_update.py @@ -631,8 +631,17 @@ def setup(self): import ckan.model as model model.repo.rebuild_db() + @classmethod + def setup_class(cls): + if not p.plugin_loaded('image_view'): + p.load('image_view') + if not p.plugin_loaded('recline_view'): + p.load('recline_view') + @classmethod def teardown_class(cls): + p.unload('image_view') + p.unload('recline_view') helpers.reset_db() def test_url_only(self): @@ -723,6 +732,7 @@ def test_extra_gets_deleted_on_extra_only_update(self): assert_equals(res_returned['anotherfield'], 'second') assert 'newfield' not in res_returned + @helpers.change_config('ckan.views.default_views', 'image_view recline_view') def test_resource_format_update(self): dataset = factories.Dataset() From 839ba128c432e8ee8afe5913da6725cda0a5ef93 Mon Sep 17 00:00:00 2001 From: Sergey Motornyuk Date: Tue, 2 May 2017 13:09:29 +0300 Subject: [PATCH 05/35] Restrict access to `members` and `bulk_actions` After this fix only users with permission `bulk_update_public` will be able to visit `bulc_process` page and only those who have `group_edit_permissions' will be able to visit `members` page --- ckan/controllers/group.py | 14 ++++++++++---- ckan/logic/auth/update.py | 30 ++++++++++++++++++++++++------ 2 files changed, 34 insertions(+), 10 deletions(-) diff --git a/ckan/controllers/group.py b/ckan/controllers/group.py index 345544d1e94..a6c0a184559 100644 --- a/ckan/controllers/group.py +++ b/ckan/controllers/group.py @@ -405,6 +405,7 @@ def bulk_process(self, id): data_dict = {'id': id} try: + self._check_access('bulk_update_public', context, data_dict) # Do not query for the group datasets when dictizing, as they will # be ignored and get requested on the controller anyway data_dict['include_datasets'] = False @@ -413,7 +414,7 @@ def bulk_process(self, id): except NotFound: abort(404, _('Group not found')) except NotAuthorized: - abort(401, _('Unauthorized to read group %s') % id) + abort(403, _('User %r not authorized to edit %s') % (c.user, id)) #use different form names so that ie7 can be detected form_names = set(["bulk_action.public", "bulk_action.delete", @@ -673,16 +674,21 @@ def members(self, id): 'user': c.user or c.author} try: + data_dict = {'id': id} + self._check_access('group_edit_permissions', context, data_dict) c.members = self._action('member_list')( context, {'id': id, 'object_type': 'user'} ) - data_dict = {'id': id} data_dict['include_datasets'] = False c.group_dict = self._action('group_show')(context, data_dict) - except NotAuthorized: - abort(401, _('Unauthorized to delete group %s') % '') except NotFound: abort(404, _('Group not found')) + except NotAuthorized: + abort( + 403, + _('User %r not authorized to edit members of %s') % ( + c.user, id)) + return self._render_template('group/members.html', group_type) def member_new(self, id): diff --git a/ckan/logic/auth/update.py b/ckan/logic/auth/update.py index ff527da0f92..c2f1ad37859 100644 --- a/ckan/logic/auth/update.py +++ b/ckan/logic/auth/update.py @@ -173,14 +173,32 @@ def group_edit_permissions(context, data_dict): user = context['user'] group = logic_auth.get_group_object(context, data_dict) - authorized = authz.has_user_permission_for_group_or_org(group.id, - user, - 'update') + authorized = authz.has_user_permission_for_group_or_org( + group.id, user, 'update') if not authorized: - return {'success': False, - 'msg': _('User %s not authorized to edit permissions of group %s') % - (str(user), group.id)} + return { + 'success': False, + 'msg': _('User %s not authorized to' + ' edit permissions of group %s') % + (str(user), group.id)} + else: + return {'success': True} + + +def organization_edit_permissions(context, data_dict): + user = context['user'] + group = logic_auth.get_group_object(context, data_dict) + + authorized = authz.has_user_permission_for_group_or_org( + group.id, user, 'update') + + if not authorized: + return { + 'success': False, + 'msg': _('User %s not authorized to edit' + ' permissions of organization %s') % + (str(user), group.id)} else: return {'success': True} From 5b1e0e5ba09d6fc83cc9835b2bcdbeffb0a87e1c Mon Sep 17 00:00:00 2001 From: Sergey Motornyuk Date: Tue, 2 May 2017 14:27:25 +0300 Subject: [PATCH 06/35] test fixes --- ckan/controllers/group.py | 4 ++-- ckan/logic/auth/update.py | 17 ----------------- 2 files changed, 2 insertions(+), 19 deletions(-) diff --git a/ckan/controllers/group.py b/ckan/controllers/group.py index a6c0a184559..c2c31cd0f9d 100644 --- a/ckan/controllers/group.py +++ b/ckan/controllers/group.py @@ -405,7 +405,7 @@ def bulk_process(self, id): data_dict = {'id': id} try: - self._check_access('bulk_update_public', context, data_dict) + self._check_access('bulk_update_public', context, {'org_id': id}) # Do not query for the group datasets when dictizing, as they will # be ignored and get requested on the controller anyway data_dict['include_datasets'] = False @@ -675,7 +675,7 @@ def members(self, id): try: data_dict = {'id': id} - self._check_access('group_edit_permissions', context, data_dict) + check_access('group_edit_permissions', context, data_dict) c.members = self._action('member_list')( context, {'id': id, 'object_type': 'user'} ) diff --git a/ckan/logic/auth/update.py b/ckan/logic/auth/update.py index c2f1ad37859..c6aff43d94a 100644 --- a/ckan/logic/auth/update.py +++ b/ckan/logic/auth/update.py @@ -186,23 +186,6 @@ def group_edit_permissions(context, data_dict): return {'success': True} -def organization_edit_permissions(context, data_dict): - user = context['user'] - group = logic_auth.get_group_object(context, data_dict) - - authorized = authz.has_user_permission_for_group_or_org( - group.id, user, 'update') - - if not authorized: - return { - 'success': False, - 'msg': _('User %s not authorized to edit' - ' permissions of organization %s') % - (str(user), group.id)} - else: - return {'success': True} - - @logic.auth_allow_anonymous_access def user_update(context, data_dict): user = context['user'] From 109d47c1fe852085eb9bf3ba8e34d6bc6e57e3b1 Mon Sep 17 00:00:00 2001 From: Jinfei Fan Date: Wed, 7 Jun 2017 14:11:07 -0400 Subject: [PATCH 07/35] fix broken language toggle url when there is params in current url --- ckan/lib/helpers.py | 7 ++++++- ckan/templates/snippets/language_selector.html | 3 +-- ckan/tests/controllers/test_package.py | 10 ++++++++++ 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/ckan/lib/helpers.py b/ckan/lib/helpers.py index ba6ee213798..0868edda8b1 100644 --- a/ckan/lib/helpers.py +++ b/ckan/lib/helpers.py @@ -116,7 +116,7 @@ def get_site_protocol_and_host(): If `ckan.site_url` is set like this:: ckan.site_url = http://example.com - + Then this function would return a tuple `('http', 'example.com')` If the setting is missing, `(None, None)` is returned instead. @@ -307,6 +307,11 @@ def full_current_url(): return (url_for(request.environ['CKAN_CURRENT_URL'], qualified=True)) +def current_url(): + ''' Returns current url unquoted''' + return urllib.unquote(request.environ['CKAN_CURRENT_URL']) + + def lang(): ''' Return the language code for the current locale eg `en` ''' return request.environ.get('CKAN_LANG') diff --git a/ckan/templates/snippets/language_selector.html b/ckan/templates/snippets/language_selector.html index dfe62c1686a..fa48b643ce2 100644 --- a/ckan/templates/snippets/language_selector.html +++ b/ckan/templates/snippets/language_selector.html @@ -1,10 +1,9 @@ -{% set current_url = request.environ.CKAN_CURRENT_URL %} {% set current_lang = request.environ.CKAN_LANG %}