Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HDX-10056 allow sysadmins to add tags starting with "crisis-" #6426

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion ckanext-hdx_package/ckanext/hdx_package/helpers/caching.py
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,6 @@ def cached_approved_tags_list():
return tags


def invalidate_approved_tags_list():
def invalidate_cached_approved_tags():
log.info('Invalidating cache for approved tags list')
cached_approved_tags_list.invalidate()
Original file line number Diff line number Diff line change
Expand Up @@ -714,13 +714,19 @@ def hdx_dataseries_title_validator(value, context):


def hdx_tag_name_approved_validator(key, data, errors, context):
user = context.get('user')
ignore_auth = context.get('ignore_auth')
allowed_to_add_crisis_tags = ignore_auth or (user and authz.is_sysadmin(user))

tag_name = data.get(key)

approved_tags = get_action('cached_approved_tags_list')(context, {})

if tag_name not in approved_tags:
approved_tags_url = 'https://data.humdata.org/rdr/spreadsheets/approved-tags'
errors[key].append("Tag name '{}' is not in the approved list of tags. Check the list at: {}".format(tag_name, approved_tags_url))
# Allow sysadmins to add tags starting with "crisis-"
if not (allowed_to_add_crisis_tags and tag_name.startswith('crisis-') and tag_name != 'crisis-'):
approved_tags_url = 'https://data.humdata.org/rdr/spreadsheets/approved-tags'
errors[key].append("Tag name '{}' is not in the approved list of tags. Check the list at: {}".format(tag_name, approved_tags_url))

def hdx_update_last_modified_if_url_changed(key: FlattenKey, data: FlattenDataDict,
errors: FlattenErrorDict, context: Context) -> Any:
Expand Down
22 changes: 13 additions & 9 deletions ckanext-hdx_package/ckanext/hdx_package/helpers/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from ckanext.hdx_package.helpers.freshness_calculator import FreshnessCalculator


import ckan.authz as new_authz
import ckan.lib.base as base
import ckan.lib.helpers as h
import ckan.model as model
Expand Down Expand Up @@ -203,6 +204,10 @@ def hdx_tag_autocomplete_list(context, data_dict):
searched. If the ``vocabulary_id`` argument is given then only tags
belonging to that vocabulary will be searched instead.

This was changed to return a list of approved tag names that contain a given string.
This searches for tags in the approved list that contain the provided query string. If the query string starts
with "crisis-" and the user is a sysadmin, the query itself can be added as a new tag.

:param query: the string to search for
:type query: string
:param vocabulary_id: the id or name of the tag vocabulary to search in
Expand All @@ -220,17 +225,16 @@ def hdx_tag_autocomplete_list(context, data_dict):

'''
_check_access('tag_autocomplete', context, data_dict)
data_dict.update({
'vocabulary_id': 'Topics',

})
matching_tags, count = _tag_search(context, data_dict)
if matching_tags:
return [tag.name for tag in matching_tags]
else:
return []
approved_tags = get_action('cached_approved_tags_list')(context, {})
query = data_dict.get('q', '').lower()
matching_tags = [tag for tag in approved_tags if query in tag.lower()]

# Allow sysadmins to add tags starting with "crisis-"
if new_authz.is_sysadmin(c.user) and query.startswith('crisis-') and query != 'crisis-':
matching_tags.append(query)

# code copied from get.py line 1748
return matching_tags


def hdx_retrieve_approved_tags(context, data_dict):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,34 @@ def test_create_valid_tags(self):
assert 'children' in [tag['name'] for tag in pkg.get('tags')]
assert 'boys' in [tag['name'] for tag in pkg.get('tags')]

def test_create_valid_crisis_tags(self):
package = {
"package_creator": "test function",
"private": False,
"dataset_date": "[1960-01-01 TO 2012-12-31]",
"caveats": "These are the caveats",
"license_other": "TEST OTHER LICENSE",
"methodology": "This is a test methodology",
"dataset_source": "World Bank",
"license_id": "hdx-other",
"notes": "This is a test activity 6",
"groups": [{"name": "roger"}],
"owner_org": "hdx-test-org",
'name': 'test_activity_6',
'title': 'Test Activity 6',
'tags': [{'name': 'crisis-ebola'}, {'name': 'crisis-response'}]
}

context = {'model': model, 'session': model.Session, 'user': 'testsysadmin'}

self._get_action('package_create')(context, package)

pkg = self._get_action('package_show')(context, {'id': package['name']})

assert len(pkg.get('tags')) == 2
assert 'crisis-ebola' in [tag['name'] for tag in pkg.get('tags')]
assert 'crisis-response' in [tag['name'] for tag in pkg.get('tags')]

def test_create_invalid_tags(self):
package = {
"package_creator": "test function",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -385,8 +385,10 @@ def test_hdx_package_tags_validation(self):
}

testsysadmin = model.User.by_name('testsysadmin')
joeadmin = model.User.by_name('joeadmin')

context = {'ignore_auth': True, 'model': model, 'session': model.Session, 'user': 'testsysadmin'}
context_user = {'model': model, 'session': model.Session, 'user': 'joeadmin', 'auth_user_obj': joeadmin}

pkg_dict = self._get_action('package_create')(context, package)

Expand All @@ -397,13 +399,29 @@ def test_hdx_package_tags_validation(self):
assert len(modified_package.get('tags')) == 1
assert 'children' in [tag['name'] for tag in modified_package.get('tags')]

data_dict = self._modify_field(context, testsysadmin, package['name'], 'tags',
[{'name': 'crisis-ebola'}, {'name': 'children'}])
modified_package = data_dict.get('modified_package')

assert len(modified_package.get('tags')) == 2
assert 'crisis-ebola' in [tag['name'] for tag in modified_package.get('tags')]
assert 'children' in [tag['name'] for tag in modified_package.get('tags')]

try:
self._modify_field(context, testsysadmin, package['name'], 'tags', [{'name': 'invalid_tag1'}, {'name': 'invalid_tag2'}])
except ValidationError as e:
assert 'tags' in e.error_dict, 'package_update should fail when using invalid tags'
assert len(e.error_dict.get('tags')) == 2, 'There should be two invalid tags'
assert "Tag name 'invalid_tag1' is not in the approved list of tags" in e.error_dict.get('tags')[0]

try:
self._modify_field(context_user, joeadmin, package['name'], 'tags', [{'name': 'crisis-food'}])
except ValidationError as e:
assert 'tags' in e.error_dict, 'Only sysadmins are allowed to add tags starting with "crisis-"'
assert "Tag name 'crisis-food' is not in the approved list of tags" in e.error_dict.get('tags')[0], \
'Only sysadmins are allowed to add tags starting with "crisis-"'


def _modify_field(self, context, user, package_id, key, value):
modified_fields = {'id': package_id,
key: value,
Expand Down
7 changes: 7 additions & 0 deletions ckanext-hdx_theme/ckanext/hdx_theme/helpers/actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
import ckanext.hdx_theme.hxl.transformers.transformers as transformers
import ckan.authz as authz

from ckan.types import Context, DataDict

from ckanext.activity.model.activity import Activity
from ckanext.hdx_theme.helpers.hdx_stats import HDXStatsHelper
from ckanext.hdx_theme.hxl.proxy import do_hxl_transformation, transform_response_to_dict_list
Expand Down Expand Up @@ -163,6 +165,11 @@ def invalidate_cached_resource_id_apihighways(context, data_dict):
caching.invalidate_cached_resource_id_apihighways()


def invalidate_cached_approved_tags(context: Context, data_dict: DataDict):
_check_access('invalidate_cached_approved_tags', context, data_dict)
caching.invalidate_cached_approved_tags()


def invalidate_region(context, data_dict):
_check_access('invalidate_region', context, data_dict)

Expand Down
5 changes: 5 additions & 0 deletions ckanext-hdx_theme/ckanext/hdx_theme/helpers/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

# from ckan.logic.auth.update import user_generate_apikey
from ckan.logic.auth import get_user_object
from ckan.types import Context, DataDict
from ckanext.hdx_users.helpers.permissions import Permissions

_ = tk._
Expand Down Expand Up @@ -64,6 +65,10 @@ def invalidate_cached_resource_id_apihighways(context, data_dict):
return {'success': False, 'msg': _('Only sysadmins can invalidate apihighways cache')}


def invalidate_cached_approved_tags(context: Context, data_dict: DataDict) -> dict:
return {'success': False, 'msg': _('Only sysadmins can invalidate approved tags cache')}


def invalidate_region(context, data_dict):
return {'success': False, 'msg': _('Only sysadmins can invalidate region cache')}

Expand Down
2 changes: 2 additions & 0 deletions ckanext-hdx_theme/ckanext/hdx_theme/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,7 @@ def get_actions(self):
'invalidate_cache_for_groups': hdx_actions.invalidate_cache_for_groups,
'invalidate_cache_for_organizations': hdx_actions.invalidate_cache_for_organizations,
'invalidate_cached_resource_id_apihighways': hdx_actions.invalidate_cached_resource_id_apihighways,
'invalidate_cached_approved_tags': hdx_actions.invalidate_cached_approved_tags,
'invalidate_region': hdx_actions.invalidate_region,
'hdx_basic_user_info': hdx_actions.hdx_basic_user_info,
'member_list': hdx_actions.member_list,
Expand Down Expand Up @@ -310,6 +311,7 @@ def get_auth_functions(self):
'invalidate_cache_for_groups': auth.invalidate_cache_for_groups,
'invalidate_cache_for_organizations': auth.invalidate_cache_for_organizations,
'invalidate_cached_resource_id_apihighways': auth.invalidate_cached_resource_id_apihighways,
'invalidate_cached_approved_tags': auth.invalidate_cached_approved_tags,
'invalidate_region': auth.invalidate_region,
'hdx_user_statistics': auth.hdx_user_statistics,
'hdx_push_general_stats': auth.hdx_push_general_stats,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -709,11 +709,7 @@ <h3>Metadata</h3>
{% set approved_tags = h.hdx_get_approved_tags_list() %}
{% set selected_tags = data.tag_string.split(', ') if data.tag_string else '' %}
<div data-module="hdx_form_element_manager" data-module-element_name="tag_string" data-module-broadcast_change="true" data-module-required="requestdata">
{% if approved_tags %}
{{ form.select('tag_string', id='field_tag_string', label=_('Tags'), options=approved_tags, selected=selected_tags, error=errors.tag_string, classes=['mb-3', 'tags-select'], attrs={'class':'choices-orange', 'multiple':'true' }) }}
{% else %}
{{ form.input('tag_string', id='field_tag_string', label=_('Tags'), value=data.tag_string, error=errors.tag_string, classes=['', 'mb-3', 'tags-select'], attrs=tag_input_attrs) }}
{% endif %}
{{ form.input('tag_string', id='field_tag_string', label=_('Tags'), value=data.tag_string, error=errors.tag_string, classes=['', 'mb-3', 'tags-select'], attrs=tag_input_attrs) }}
<div data-module="hdx_tag_recommender" data-module-tag_input_selector="#field_tag_string"
data-module-recommended_tag_wrapper_selector="#recommended-tags-wrapper" class="mb-3">
<div id="recommended-tags-wrapper" class="recommended-tags-wrapper" style="display: none;">
Expand Down
Loading