From b2311a1f4517cfaf3db8e0196093f70e04f05ced Mon Sep 17 00:00:00 2001 From: cormac hallinan Date: Wed, 8 May 2024 13:46:57 +0000 Subject: [PATCH 1/7] improving publisher search query --- ckanext/iati/helpers.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ckanext/iati/helpers.py b/ckanext/iati/helpers.py index 1da12a3..8d946cb 100644 --- a/ckanext/iati/helpers.py +++ b/ckanext/iati/helpers.py @@ -141,7 +141,7 @@ def get_publisher_obj_extra_fields_pub_ids(group_dict): for ex in group_dict: if ex in formatter_map.keys(): extras[ex] = formatter_map[ex](group_dict.get(ex, "")) - + log.info(group_dict) extras['publisher_iati_id'] = group_dict['publisher_iati_id'] return extras @@ -310,7 +310,7 @@ def normalize_publisher_name(name): return name[4:] + ', The' return name -def organization_list(include_extras=False): +def organization_list(include_extras=True): data_dict = {'all_fields': True, 'sort': 'title asc'} if include_extras: data_dict['include_extras'] = include_extras From c410f3ab6844272a3821d5bce53f7fbd9be9307d Mon Sep 17 00:00:00 2001 From: cormac hallinan Date: Wed, 8 May 2024 13:48:05 +0000 Subject: [PATCH 2/7] improving publisher search query --- ckanext/iati/logic/action.py | 186 ++++++++++++++++------------------- 1 file changed, 86 insertions(+), 100 deletions(-) diff --git a/ckanext/iati/logic/action.py b/ckanext/iati/logic/action.py index ed1289f..be9c65f 100644 --- a/ckanext/iati/logic/action.py +++ b/ckanext/iati/logic/action.py @@ -2,7 +2,7 @@ import json import csv import tempfile -from urllib.parse import urljoin +from urllib.parse import urljoin, parse_qs import inspect from ckan.plugins.toolkit import config import sqlalchemy @@ -13,6 +13,8 @@ import ckan.lib.helpers as h import ckan.lib.dictization.model_dictize as model_dictize import ckan.model as model +from ckan.logic import schema, get_action +from ckan.model import Group, GroupExtra, Package, Member import ckan.logic.action.get as get_core import ckan.logic.action.create as create_core import ckan.logic.action.update as update_core @@ -21,7 +23,8 @@ import ckanext.iati.emailer as emailer import ckanext.iati.helpers as hlp import ckanext.iati.model as iati_model -from sqlalchemy import and_ +from sqlalchemy import and_, func, or_ +import sqlalchemy as sa from ckanext.iati.logic import publisher_tasks from paste.deploy.converters import asbool @@ -378,109 +381,92 @@ def _send_activation_notification_email(context, organization_dict): def _custom_group_or_org_list(context, data_dict, is_org=True): """ - Custom oprg search by publisher_iati_id and sort by publisher_first_published + Custom group or organization list function. """ + log.error(data_dict) model = context['model'] - api = context.get('api_version') - groups = data_dict.get('groups') - group_type = data_dict.get('type', 'group') - ref_group_by = 'id' if api == 2 else 'name' - pagination_dict = {} - limit = data_dict.get('limit', None) - if limit: - pagination_dict['limit'] = data_dict['limit'] - offset = data_dict.get('offset') - if offset: - pagination_dict['offset'] = data_dict['offset'] - if pagination_dict: - pagination_dict, errors = _validate( - data_dict, logic.schema.default_pagination_schema(), context) - if errors: - raise ValidationError(errors) - sort = data_dict.get('sort') or 'title' - q = data_dict.get('q', '').strip() + group_type = data_dict.get('type', 'organization') - all_fields = asbool(data_dict.get('all_fields', None)) + limit = data_dict.get('limit', 10) + offset = data_dict.get('offset', 0) - if all_fields: - # all_fields is really computationally expensive, so need a tight limit - max_limit = int(config.get( - 'ckan.group_and_organization_list_all_fields_max', 50)) + sort = data_dict.get('sort', 'title') + log.error(sort) + if sort: + sort_order = 'asc' if 'asc' in sort else 'desc' + sort_field_name = sort.strip().split(' ')[0] else: - max_limit = int(config.get('ckan.group_and_organization_list_max', 1000)) - - if limit and int(limit) > max_limit: - limit = max_limit - - # order_by deprecated in ckan 1.8 - # if it is supplied and sort isn't use order_by and raise a warning - order_by = data_dict.get('order_by', '') - if order_by: - log.warn('`order_by` deprecated please use `sort`') - if not data_dict.get('sort'): - sort = order_by - - # if the sort is packages and no sort direction is supplied we want to do a - # reverse sort to maintain compatibility. - if sort.strip() in ('packages', 'package_count'): - sort = 'package_count desc' - - sort_info = get_core._unpick_search(sort, - allowed_fields=['name', 'packages', - 'package_count', 'title', 'publisher_first_publish_date'], - total=1) + sort_order = None + sort_field_name = None - if sort_info and sort_info[0][0] == 'package_count': - query = model.Session.query(model.Group.id, - model.Group.name, - sqlalchemy.func.count(model.Group.id)).join(model.GroupExtra) - - query = query.filter(model.Member.group_id == model.Group.id) \ - .filter(model.Member.table_id == model.Package.id) \ - .filter(model.Member.table_name == 'package') \ - .filter(model.Package.state == 'active') + q = data_dict.get('q', '').strip() + publisher_country = None + publisher_iati_id = None + if 'publisher_country' in q or 'publisher_iati_id' in q: + filter_args = parse_qs(q) + publisher_country = filter_args.get("publisher_country", [None])[0] + publisher_iati_id = filter_args.get("publisher_iati_id", [None])[0] else: - query = model.Session.query(model.Group.id, - model.Group.name).join(model.GroupExtra) + name_query = q + + query = model.Session.query(Group.id, Group.name, Group.title) + query = query.filter(Group.state == 'active', Group.is_organization == is_org) + query = query.filter(Group.type == group_type) + + if name_query: + general_search_pattern = f"%{name_query}%" + query = query.filter( + or_( + model.Group.name.like(general_search_pattern), + model.Group.title.like(general_search_pattern), + ) + ) - query = query.filter(_and_(model.Group.state == 'active', model.GroupExtra.key == 'publisher_iati_id')) + group_extra_sort_fields = ["publisher_first_publish_date", "publisher_iati_id", "publisher_organization_type", "publisher_country"] + if publisher_country: + query = query.join( + model.GroupExtra, + sa.and_( + model.GroupExtra.group_id == model.Group.id, + model.GroupExtra.key == 'publisher_country', + ), + isouter=True + ).filter( + model.GroupExtra.value.like(f"%{publisher_country}%") + ) - if groups: - query = query.filter(model.Group.name.in_(groups)) - if q: - q = '%{0}%'.format(q) - query = query.filter(_or_( - model.Group.name.ilike(q), - model.Group.title.ilike(q), - model.GroupExtra.value.ilike(q), - )) + if publisher_iati_id: + query = query.join( + model.GroupExtra, + sa.and_( + model.GroupExtra.group_id == model.Group.id, + model.GroupExtra.key == 'publisher_iati_id', + ), + isouter=True, + ).filter( + model.GroupExtra.value.like(f"%{publisher_iati_id}%") + ) - query = query.filter(model.Group.is_organization == is_org) - query = query.filter(model.Group.type == group_type) - - if sort_info: - sort_field = sort_info[0][0] - sort_direction = sort_info[0][1] - if sort_field == 'package_count': - query = query.group_by(model.Group.id, model.Group.name) - sort_model_field = sqlalchemy.func.count(model.Group.id) - elif sort_field == 'name': - sort_model_field = model.Group.name - elif sort_field == 'title': - sort_model_field = model.Group.title - elif sort_field == "publisher_first_publish_date": - sort_model_field = model.GroupExtra.value - query = query.subquery() - query = model.Session.query(model.Group.id, model.Group.name).join( - query, query.c.id == model.Group.id).join(model.GroupExtra).filter( - model.GroupExtra.key == 'publisher_first_publish_date') - else: - sort_model_field = model.Group.title + if sort_field_name in group_extra_sort_fields: + extra_alias = sa.alias(GroupExtra, name=f"group_extra_{sort_field_name}") + query = query.join( + extra_alias, + sa.and_( + extra_alias.c.group_id == Group.id, + extra_alias.c.key == sort_field_name + ) + ) - if sort_direction == 'asc': - query = query.order_by(sqlalchemy.asc(sort_model_field)) + if sort_field_name in group_extra_sort_fields: + if sort_order == 'asc': + query = query.order_by(sa.asc(extra_alias.c.value)) else: - query = query.order_by(sqlalchemy.desc(sort_model_field)) + query = query.order_by(sa.desc(extra_alias.c.value)) + else: + if sort_field_name == 'name': + query = query.order_by(sa.asc(Group.name) if sort_order == 'asc' else sa.desc(Group.name)) + else: + query = query.order_by(sa.asc(Group.title) if sort_order == 'asc' else sa.desc(Group.title)) if limit: query = query.limit(int(limit)) @@ -489,18 +475,18 @@ def _custom_group_or_org_list(context, data_dict, is_org=True): groups = query.distinct().all() + all_fields = asbool(data_dict.get('all_fields', False)) if all_fields: action = 'organization_show' if is_org else 'group_show' group_list = [] for group in groups: - data_dict['id'] = group.id - for key in ('include_extras', 'include_tags', 'include_users', - 'include_groups', 'include_followers'): - if key not in data_dict: - data_dict[key] = False - - group_list.append(logic.get_action(action)(context, data_dict)) + item_data_dict = { + 'id': group.id, + 'include_extras': True, + } + group_list.append(get_action(action)(context, item_data_dict)) else: + ref_group_by = 'id' if context.get('api_version', 1) == 2 else 'name' group_list = [getattr(group, ref_group_by) for group in groups] return group_list From c4e61fa650dc1823f306872c5c6ef3399028baf4 Mon Sep 17 00:00:00 2001 From: cormac hallinan Date: Fri, 31 May 2024 15:56:33 +0000 Subject: [PATCH 3/7] adding publisher state --- ckanext/iati/helpers.py | 6 +++- ckanext/iati/logic/action.py | 19 ++++++++---- .../snippets/organization_list_ids.html | 30 +++++++++++-------- 3 files changed, 35 insertions(+), 20 deletions(-) diff --git a/ckanext/iati/helpers.py b/ckanext/iati/helpers.py index 8d946cb..6705adb 100644 --- a/ckanext/iati/helpers.py +++ b/ckanext/iati/helpers.py @@ -129,8 +129,11 @@ def get_publisher_obj_extra_fields(group_dict): return extras def get_publisher_obj_extra_fields_pub_ids(group_dict): + log.info('----- get_publisher_obj_extra_fields_pub_ids -----') + log.info(f"{group_dict['name']} with state {group_dict['state']}") extras = {} if not group_dict: + log.info('not group_dict') return extras formatter_map = { @@ -141,8 +144,9 @@ def get_publisher_obj_extra_fields_pub_ids(group_dict): for ex in group_dict: if ex in formatter_map.keys(): extras[ex] = formatter_map[ex](group_dict.get(ex, "")) - log.info(group_dict) + extras['publisher_iati_id'] = group_dict['publisher_iati_id'] + log.info(f'Returning ---> {extras}') return extras def is_route_active(menu_item): diff --git a/ckanext/iati/logic/action.py b/ckanext/iati/logic/action.py index be9c65f..b94e15d 100644 --- a/ckanext/iati/logic/action.py +++ b/ckanext/iati/logic/action.py @@ -379,11 +379,13 @@ def _send_activation_notification_email(context, organization_dict): log.debug('[email] Publisher activated notification email sent to user {0}'.format(user.name)) -def _custom_group_or_org_list(context, data_dict, is_org=True): +def _custom_group_or_org_list(context, data_dict, is_sysadmin, is_org=True): """ Custom group or organization list function. """ log.error(data_dict) + log.error(context) + model = context['model'] group_type = data_dict.get('type', 'organization') @@ -402,6 +404,7 @@ def _custom_group_or_org_list(context, data_dict, is_org=True): q = data_dict.get('q', '').strip() publisher_country = None publisher_iati_id = None + name_query = None if 'publisher_country' in q or 'publisher_iati_id' in q: filter_args = parse_qs(q) publisher_country = filter_args.get("publisher_country", [None])[0] @@ -409,9 +412,12 @@ def _custom_group_or_org_list(context, data_dict, is_org=True): else: name_query = q - query = model.Session.query(Group.id, Group.name, Group.title) - query = query.filter(Group.state == 'active', Group.is_organization == is_org) - query = query.filter(Group.type == group_type) + query = model.Session.query(model.Group.id, model.Group.name, model.Group.title, model.Group.state) + if is_sysadmin: + query = query.filter(or_(Group.state == 'active', model.Group.state == 'approval_needed'), Group.is_organization == is_org) + else: + query = query.filter(model.Group.state == 'active', model.Group.is_organization == is_org) + query = query.filter(model.Group.type == group_type) if name_query: general_search_pattern = f"%{name_query}%" @@ -488,7 +494,7 @@ def _custom_group_or_org_list(context, data_dict, is_org=True): else: ref_group_by = 'id' if context.get('api_version', 1) == 2 else 'name' group_list = [getattr(group, ref_group_by) for group in groups] - + log.info(group_list) return group_list @@ -572,7 +578,8 @@ def organization_list(context, data_dict): p.toolkit.check_access('organization_list', context, data_dict) data_dict['groups'] = data_dict.pop('organizations', []) data_dict.setdefault('type', 'organization') - return _custom_group_or_org_list(context, data_dict, is_org=True) + is_sysadmin = authz.is_sysadmin(g.user) + return _custom_group_or_org_list(context, data_dict, is_sysadmin, is_org=True) @p.toolkit.side_effect_free diff --git a/ckanext/iati/theme/templates/organization/snippets/organization_list_ids.html b/ckanext/iati/theme/templates/organization/snippets/organization_list_ids.html index 73a049b..8890959 100644 --- a/ckanext/iati/theme/templates/organization/snippets/organization_list_ids.html +++ b/ckanext/iati/theme/templates/organization/snippets/organization_list_ids.html @@ -20,26 +20,30 @@ HQ Country / Region {% endif %} Datasets + State + {% for organization in organizations %} {% set extra_fields = h.get_publisher_obj_extra_fields_pub_ids(organization) %} - - {% if is_admin_page or organization.package_count > 0 or 'dashboard' in request.url %} - + + {% if organization.title %} {{ h.normalize_publisher_name(organization.title) }} - {{ extra_fields.publisher_iati_id }} - {{ extra_fields.publisher_organization_type }} - {% if is_admin_page %} - {{ extra_fields.publisher_first_publish_date }} - {% else %} - {{ extra_fields.publisher_country }} - {% endif %} - {{ organization.package_count }} - - {% endif %} + {% else %} + {{ h.normalize_publisher_name(organization.name) }} + {% endif %} + {{ extra_fields.publisher_iati_id }} + {{ extra_fields.publisher_organization_type }} + {{ extra_fields.publisher_country }} + {{ organization.package_count }} + {% if organization.state == 'approval_needed' %} + approval needed + {% else %} + {{ organization.state }} + {% endif %} + {% endfor %} From b745a64b4cf0c054b735ebaec1e82ec26b3a91a2 Mon Sep 17 00:00:00 2001 From: cormac hallinan Date: Wed, 12 Jun 2024 12:00:41 +0000 Subject: [PATCH 4/7] improving query to ignore case sensitive --- ckanext/iati/logic/action.py | 52 ++++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 23 deletions(-) diff --git a/ckanext/iati/logic/action.py b/ckanext/iati/logic/action.py index b94e15d..34fc4c6 100644 --- a/ckanext/iati/logic/action.py +++ b/ckanext/iati/logic/action.py @@ -388,12 +388,21 @@ def _custom_group_or_org_list(context, data_dict, is_sysadmin, is_org=True): model = context['model'] group_type = data_dict.get('type', 'organization') - limit = data_dict.get('limit', 10) offset = data_dict.get('offset', 0) - sort = data_dict.get('sort', 'title') - log.error(sort) + + # Enforce max limit + max_limit = int(config.get('ckan.group_and_organization_list_max', 1000)) + if limit and int(limit) > max_limit: + limit = max_limit + + # Validate pagination + pagination_dict = {'limit': limit, 'offset': offset} + pagination_dict, errors = _validate(data_dict, logic.schema.default_pagination_schema(), context) + if errors: + raise ValidationError(errors) + if sort: sort_order = 'asc' if 'asc' in sort else 'desc' sort_field_name = sort.strip().split(' ')[0] @@ -412,52 +421,49 @@ def _custom_group_or_org_list(context, data_dict, is_sysadmin, is_org=True): else: name_query = q - query = model.Session.query(model.Group.id, model.Group.name, model.Group.title, model.Group.state) - if is_sysadmin: - query = query.filter(or_(Group.state == 'active', model.Group.state == 'approval_needed'), Group.is_organization == is_org) - else: - query = query.filter(model.Group.state == 'active', model.Group.is_organization == is_org) - query = query.filter(model.Group.type == group_type) + query = model.Session.query(Group.id, Group.name, Group.title) + query = query.filter(Group.state == 'active', Group.is_organization == is_org) + query = query.filter(Group.type == group_type) if name_query: general_search_pattern = f"%{name_query}%" query = query.filter( or_( - model.Group.name.like(general_search_pattern), - model.Group.title.like(general_search_pattern), + model.Group.name.ilike(general_search_pattern), + model.Group.title.ilike(general_search_pattern), ) ) group_extra_sort_fields = ["publisher_first_publish_date", "publisher_iati_id", "publisher_organization_type", "publisher_country"] if publisher_country: query = query.join( - model.GroupExtra, - sa.and_( - model.GroupExtra.group_id == model.Group.id, - model.GroupExtra.key == 'publisher_country', + GroupExtra, + and_( + GroupExtra.group_id == Group.id, + GroupExtra.key == 'publisher_country', ), isouter=True ).filter( - model.GroupExtra.value.like(f"%{publisher_country}%") + GroupExtra.value.ilike(f"%{publisher_country}%") ) if publisher_iati_id: query = query.join( - model.GroupExtra, - sa.and_( - model.GroupExtra.group_id == model.Group.id, - model.GroupExtra.key == 'publisher_iati_id', + GroupExtra, + and_( + GroupExtra.group_id == Group.id, + GroupExtra.key == 'publisher_iati_id', ), isouter=True, ).filter( - model.GroupExtra.value.like(f"%{publisher_iati_id}%") + GroupExtra.value.ilike(f"%{publisher_iati_id}%") ) if sort_field_name in group_extra_sort_fields: extra_alias = sa.alias(GroupExtra, name=f"group_extra_{sort_field_name}") query = query.join( extra_alias, - sa.and_( + and_( extra_alias.c.group_id == Group.id, extra_alias.c.key == sort_field_name ) @@ -494,7 +500,7 @@ def _custom_group_or_org_list(context, data_dict, is_sysadmin, is_org=True): else: ref_group_by = 'id' if context.get('api_version', 1) == 2 else 'name' group_list = [getattr(group, ref_group_by) for group in groups] - log.info(group_list) + return group_list From 935865833c590e8c28fd51a9744b8e77eeab318a Mon Sep 17 00:00:00 2001 From: cormac hallinan Date: Tue, 25 Jun 2024 09:34:36 +0000 Subject: [PATCH 5/7] sort by created --- ckanext/iati/helpers.py | 3 --- ckanext/iati/logic/action.py | 13 ++++++++----- .../iati/theme/templates/organization/index.html | 2 +- .../snippets/organization_list_ids.html | 4 +++- 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/ckanext/iati/helpers.py b/ckanext/iati/helpers.py index 6705adb..415d1a0 100644 --- a/ckanext/iati/helpers.py +++ b/ckanext/iati/helpers.py @@ -129,8 +129,6 @@ def get_publisher_obj_extra_fields(group_dict): return extras def get_publisher_obj_extra_fields_pub_ids(group_dict): - log.info('----- get_publisher_obj_extra_fields_pub_ids -----') - log.info(f"{group_dict['name']} with state {group_dict['state']}") extras = {} if not group_dict: log.info('not group_dict') @@ -146,7 +144,6 @@ def get_publisher_obj_extra_fields_pub_ids(group_dict): extras[ex] = formatter_map[ex](group_dict.get(ex, "")) extras['publisher_iati_id'] = group_dict['publisher_iati_id'] - log.info(f'Returning ---> {extras}') return extras def is_route_active(menu_item): diff --git a/ckanext/iati/logic/action.py b/ckanext/iati/logic/action.py index 34fc4c6..34404f0 100644 --- a/ckanext/iati/logic/action.py +++ b/ckanext/iati/logic/action.py @@ -407,8 +407,8 @@ def _custom_group_or_org_list(context, data_dict, is_sysadmin, is_org=True): sort_order = 'asc' if 'asc' in sort else 'desc' sort_field_name = sort.strip().split(' ')[0] else: - sort_order = None - sort_field_name = None + sort_order = 'desc' + sort_field_name = 'created' q = data_dict.get('q', '').strip() publisher_country = None @@ -421,7 +421,7 @@ def _custom_group_or_org_list(context, data_dict, is_sysadmin, is_org=True): else: name_query = q - query = model.Session.query(Group.id, Group.name, Group.title) + query = model.Session.query(Group.id, Group.name, Group.title, Group.created) query = query.filter(Group.state == 'active', Group.is_organization == is_org) query = query.filter(Group.type == group_type) @@ -477,6 +477,8 @@ def _custom_group_or_org_list(context, data_dict, is_sysadmin, is_org=True): else: if sort_field_name == 'name': query = query.order_by(sa.asc(Group.name) if sort_order == 'asc' else sa.desc(Group.name)) + elif sort_field_name == 'created': + query = query.order_by(sa.asc(Group.created) if sort_order == 'asc' else sa.desc(Group.created)) else: query = query.order_by(sa.asc(Group.title) if sort_order == 'asc' else sa.desc(Group.title)) @@ -496,11 +498,12 @@ def _custom_group_or_org_list(context, data_dict, is_sysadmin, is_org=True): 'id': group.id, 'include_extras': True, } - group_list.append(get_action(action)(context, item_data_dict)) + org_all_fields = get_action(action)(context, item_data_dict) + org_all_fields['created'] = group[3].date() + group_list.append(org_all_fields) else: ref_group_by = 'id' if context.get('api_version', 1) == 2 else 'name' group_list = [getattr(group, ref_group_by) for group in groups] - return group_list diff --git a/ckanext/iati/theme/templates/organization/index.html b/ckanext/iati/theme/templates/organization/index.html index f99474a..8f14bfc 100644 --- a/ckanext/iati/theme/templates/organization/index.html +++ b/ckanext/iati/theme/templates/organization/index.html @@ -50,7 +50,7 @@ 'translated_fields': c.translated_fields, 'remove_field': c.remove_field } %} - {% snippet 'snippets/search_form.html', type='organization', not_disp_query=True, site_search_label=_('Search for Publishers'), query=c.q, sorting_selected=c.sort_by_selected, count=c.page.item_count, facets=facets, placeholder=_('Search publishers...'), show_empty=request.params, sorting=[(_('Title Ascending'), 'title asc'), (_('Title Descending'), 'title desc')] %} + {% snippet 'snippets/search_form.html', type='organization', not_disp_query=True, site_search_label=_('Search for Publishers'), query=c.q, sorting_selected=c.sort_by_selected, count=c.page.item_count, facets=facets, placeholder=_('Search publishers...'), show_empty=request.params, sorting=[(_('Created Descending'), 'created desc'), (_('Created Ascending'), 'created asc')] %} {% endblock %} diff --git a/ckanext/iati/theme/templates/organization/snippets/organization_list_ids.html b/ckanext/iati/theme/templates/organization/snippets/organization_list_ids.html index 8890959..321fa1d 100644 --- a/ckanext/iati/theme/templates/organization/snippets/organization_list_ids.html +++ b/ckanext/iati/theme/templates/organization/snippets/organization_list_ids.html @@ -20,8 +20,9 @@ HQ Country / Region {% endif %} Datasets + State - + Created @@ -43,6 +44,7 @@ {% else %} {{ organization.state }} {% endif %} + {{organization.created}} {% endfor %} From 5c825e3ff7691984075c563657ff80e85daf9c18 Mon Sep 17 00:00:00 2001 From: cormac hallinan Date: Tue, 25 Jun 2024 11:39:54 +0000 Subject: [PATCH 6/7] table header sort default --- .../fanstatic_library/scripts/tablesorter.js | 27 ++++++++++++++----- .../theme/templates/organization/index.html | 8 +++++- .../snippets/organization_list_ids.html | 17 +++++++----- 3 files changed, 37 insertions(+), 15 deletions(-) diff --git a/ckanext/iati/assets/fanstatic_library/scripts/tablesorter.js b/ckanext/iati/assets/fanstatic_library/scripts/tablesorter.js index e4a0d57..8b9be16 100644 --- a/ckanext/iati/assets/fanstatic_library/scripts/tablesorter.js +++ b/ckanext/iati/assets/fanstatic_library/scripts/tablesorter.js @@ -15,14 +15,27 @@ this.ckan.module('table-sorter', function (jQuery, _) { var given_order = $("#field-order-by").val(); console.log(given_order); if (given_order == "name asc" || given_order == "title asc"){ - // Ascending order el.tablesorter({sortList: [[0,0]]}); - }else if (given_order === "name desc" || given_order === "title desc"){ - // Descending order - el.tablesorter({sortList: [[0,1]]}); - }else{ - // This is default order - el.tablesorter({sortList: [[0,0]]}); + } else if (given_order === "name desc" || given_order === "title desc"){ + el.tablesorter({sortList: [[0,1]]}); + } else if (given_order === "publisher_iati_id asc"){ + el.tablesorter({sortList: [[1,0]]}); + } else if (given_order === "publisher_iati_id desc"){ + el.tablesorter({sortList: [[1,1]]}); + } else if (given_order === "publisher_organization_type asc"){ + el.tablesorter({sortList: [[2,0]]}); + } else if (given_order === "publisher_organization_type desc"){ + el.tablesorter({sortList: [[2,1]]}); + } else if (given_order === "publisher_country asc"){ + el.tablesorter({sortList: [[3,0]]}); + } else if (given_order === "publisher_country desc"){ + el.tablesorter({sortList: [[3,1]]}); + } else if (given_order === "created asc"){ + el.tablesorter({sortList: [[5,0]]}); + } else if (given_order === "created desc"){ + el.tablesorter({sortList: [[5,1]]}); + } else{ + el.tablesorter({sortList: [[0,0]]}); }} } }); diff --git a/ckanext/iati/theme/templates/organization/index.html b/ckanext/iati/theme/templates/organization/index.html index 8f14bfc..0023cc4 100644 --- a/ckanext/iati/theme/templates/organization/index.html +++ b/ckanext/iati/theme/templates/organization/index.html @@ -50,7 +50,13 @@ 'translated_fields': c.translated_fields, 'remove_field': c.remove_field } %} - {% snippet 'snippets/search_form.html', type='organization', not_disp_query=True, site_search_label=_('Search for Publishers'), query=c.q, sorting_selected=c.sort_by_selected, count=c.page.item_count, facets=facets, placeholder=_('Search publishers...'), show_empty=request.params, sorting=[(_('Created Descending'), 'created desc'), (_('Created Ascending'), 'created asc')] %} + {% snippet 'snippets/search_form.html', type='organization', not_disp_query=True, site_search_label=_('Search for Publishers'), query=c.q, sorting_selected=c.sort_by_selected, count=c.page.item_count, facets=facets, placeholder=_('Search publishers...'), show_empty=request.params, + sorting=[(_('Created Descending'), 'created desc'), (_('Created Ascending'), 'created asc'), + (_('Name Ascending'), 'name asc'), (_('Name Descending'), 'name desc'), + (_('IATI ID Ascending'), 'publisher_iati_id asc'), (_('IATI ID Descending'), 'publisher_iati_id desc'), + (_('Organization Type Ascending'), 'publisher_organization_type asc'), (_('publisher_organization_type Descending'), 'name desc'), + (_('Country Ascending'), 'publisher_country asc'), (_('Country Descending'), 'publisher_country desc'), + ] %} {% endblock %} diff --git a/ckanext/iati/theme/templates/organization/snippets/organization_list_ids.html b/ckanext/iati/theme/templates/organization/snippets/organization_list_ids.html index 321fa1d..9df28fe 100644 --- a/ckanext/iati/theme/templates/organization/snippets/organization_list_ids.html +++ b/ckanext/iati/theme/templates/organization/snippets/organization_list_ids.html @@ -20,9 +20,10 @@ HQ Country / Region {% endif %} Datasets - - State Created + {% if c.userobj.sysadmin %} + State + {% endif %} @@ -39,12 +40,14 @@ {{ extra_fields.publisher_organization_type }} {{ extra_fields.publisher_country }} {{ organization.package_count }} - {% if organization.state == 'approval_needed' %} - approval needed - {% else %} - {{ organization.state }} - {% endif %} {{organization.created}} + {% if c.userobj.sysadmin %} + {% if organization.state == 'approval_needed' %} + approval needed + {% else %} + {{ organization.state }} + {% endif %} + {% endif %} {% endfor %} From 16feb89b0a8afeaef23b1679bd523e67f4850383 Mon Sep 17 00:00:00 2001 From: cormac hallinan Date: Mon, 9 Sep 2024 16:02:23 +0000 Subject: [PATCH 7/7] publisher search improvments --- .../fanstatic_library/scripts/tablesorter.js | 2 + .../scripts/vendor/tablesorter.js | 3 +- ckanext/iati/logic/action.py | 112 ++++++++++++++---- .../theme/templates/organization/index.html | 2 +- .../snippets/organization_list_ids.html | 2 +- 5 files changed, 93 insertions(+), 28 deletions(-) diff --git a/ckanext/iati/assets/fanstatic_library/scripts/tablesorter.js b/ckanext/iati/assets/fanstatic_library/scripts/tablesorter.js index 8b9be16..c66013a 100644 --- a/ckanext/iati/assets/fanstatic_library/scripts/tablesorter.js +++ b/ckanext/iati/assets/fanstatic_library/scripts/tablesorter.js @@ -19,8 +19,10 @@ this.ckan.module('table-sorter', function (jQuery, _) { } else if (given_order === "name desc" || given_order === "title desc"){ el.tablesorter({sortList: [[0,1]]}); } else if (given_order === "publisher_iati_id asc"){ + console.log('publisher_iati_id asc') el.tablesorter({sortList: [[1,0]]}); } else if (given_order === "publisher_iati_id desc"){ + console.log('publisher_iati_id desc') el.tablesorter({sortList: [[1,1]]}); } else if (given_order === "publisher_organization_type asc"){ el.tablesorter({sortList: [[2,0]]}); diff --git a/ckanext/iati/assets/fanstatic_library/scripts/vendor/tablesorter.js b/ckanext/iati/assets/fanstatic_library/scripts/vendor/tablesorter.js index 1eef6db..50a0e17 100755 --- a/ckanext/iati/assets/fanstatic_library/scripts/vendor/tablesorter.js +++ b/ckanext/iati/assets/fanstatic_library/scripts/vendor/tablesorter.js @@ -1,2 +1 @@ -(function($){$.extend({tablesorter:new function(){var parsers=[],widgets=[];this.defaults={cssHeader:"header",cssAsc:"headerSortUp",cssDesc:"headerSortDown",cssChildRow:"expand-child",sortInitialOrder:"asc",sortMultiSortKey:"shiftKey",sortForce:null,sortAppend:null,sortLocaleCompare:true,textExtraction:"simple",parsers:{},widgets:[],widgetZebra:{css:["even","odd"]},headers:{},widthFixed:false,cancelSelection:true,sortList:[],headerList:[],dateFormat:"us",decimal:'/\.|\,/g',onRenderHeader:null,selectorHeaders:'thead th',debug:false};function benchmark(s,d){log(s+","+(new Date().getTime()-d.getTime())+"ms");}this.benchmark=benchmark;function log(s){if(typeof console!="undefined"&&typeof console.debug!="undefined"){console.log(s);}else{alert(s);}}function buildParserCache(table,$headers){if(table.config.debug){var parsersDebug="";}if(table.tBodies.length==0)return;var rows=table.tBodies[0].rows;if(rows[0]){var list=[],cells=rows[0].cells,l=cells.length;for(var i=0;i1){arr=arr.concat(checkCellColSpan(table,headerArr,row++));}else{if(table.tHead.length==1||(cell.rowSpan>1||!r[row+1])){arr.push(cell);}}}return arr;};function checkHeaderMetadata(cell){if(($.metadata)&&($(cell).metadata().sorter===false)){return true;};return false;}function checkHeaderOptions(table,i){if((table.config.headers[i])&&(table.config.headers[i].sorter===false)){return true;};return false;}function checkHeaderOptionsSortingLocked(table,i){if((table.config.headers[i])&&(table.config.headers[i].lockedOrder))return table.config.headers[i].lockedOrder;return false;}function applyWidget(table){var c=table.config.widgets;var l=c.length;for(var i=0;i');$("tr:first td",table.tBodies[0]).each(function(){colgroup.append($('').css('width',$(this).width()));});$(table).prepend(colgroup);};}function updateHeaderSortCount(table,sortList){var c=table.config,l=sortList.length;for(var i=0;i b["+i+"]) ? 1 : 0));";};function makeSortTextDesc(i){return"((b["+i+"] < a["+i+"]) ? -1 : ((b["+i+"] > a["+i+"]) ? 1 : 0));";};function makeSortNumeric(i){return"a["+i+"]-b["+i+"];";};function makeSortNumericDesc(i){return"b["+i+"]-a["+i+"];";};function sortText(a,b){if(table.config.sortLocaleCompare)return a.localeCompare(b);return((ab)?1:0));};function sortTextDesc(a,b){if(table.config.sortLocaleCompare)return b.localeCompare(a);return((ba)?1:0));};function sortNumeric(a,b){return a-b;};function sortNumericDesc(a,b){return b-a;};function getCachedSortType(parsers,i){return parsers[i].type;};this.construct=function(settings){return this.each(function(){if(!this.tHead||!this.tBodies)return;var $this,$document,$headers,cache,config,shiftDown=0,sortOrder;this.config={};config=$.extend(this.config,$.tablesorter.defaults,settings);$this=$(this);$.data(this,"tablesorter",config);$headers=buildHeaders(this);this.config.parsers=buildParserCache(this,$headers);cache=buildCache(this);var sortCSS=[config.cssDesc,config.cssAsc];fixColumnWidth(this);$headers.click(function(e){var totalRows=($this[0].tBodies[0]&&$this[0].tBodies[0].rows.length)||0;if(!this.sortDisabled&&totalRows>0){$this.trigger("sortStart");var $cell=$(this);var i=this.column;this.order=this.count++%2;if(this.lockedOrder)this.order=this.lockedOrder;if(!e[config.sortMultiSortKey]){config.sortList=[];if(config.sortForce!=null){var a=config.sortForce;for(var j=0;j0){$this.trigger("sorton",[config.sortList]);}applyWidget(this);});};this.addParser=function(parser){var l=parsers.length,a=true;for(var i=0;i thead th, > thead td",selectorSort:"th, td",selectorRemove:".remove-me",debug:!1,headerList:[],empties:{},strings:{},parsers:[],globalize:0,imgAttr:0},css:{table:"tablesorter",cssHasChild:"tablesorter-hasChildRow",childRow:"tablesorter-childRow",colgroup:"tablesorter-colgroup",header:"tablesorter-header",headerRow:"tablesorter-headerRow",headerIn:"tablesorter-header-inner",icon:"tablesorter-icon",processing:"tablesorter-processing",sortAsc:"tablesorter-headerAsc",sortDesc:"tablesorter-headerDesc",sortNone:"tablesorter-headerUnSorted"},language:{sortAsc:"Ascending sort applied, ",sortDesc:"Descending sort applied, ",sortNone:"No sort applied, ",sortDisabled:"sorting is disabled",nextAsc:"activate to apply an ascending sort",nextDesc:"activate to apply a descending sort",nextNone:"activate to remove the sort"},regex:{templateContent:/\{content\}/g,templateIcon:/\{icon\}/g,templateName:/\{name\}/i,spaces:/\s+/g,nonWord:/\W/g,formElements:/(input|select|button|textarea)/i,chunk:/(^([+\-]?(?:\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?)?$|^0x[0-9a-f]+$|\d+)/gi,chunks:/(^\\0|\\0$)/,hex:/^0x[0-9a-f]+$/i,comma:/,/g,digitNonUS:/[\s|\.]/g,digitNegativeTest:/^\s*\([.\d]+\)/,digitNegativeReplace:/^\s*\(([.\d]+)\)/,digitTest:/^[\-+(]?\d+[)]?$/,digitReplace:/[,.'"\s]/g},string:{max:1,min:-1,emptymin:1,emptymax:-1,zero:0,none:0,"null":0,top:!0,bottom:!1},keyCodes:{enter:13},dates:{},instanceMethods:{},setup:function(t,r){if(t&&t.tHead&&0!==t.tBodies.length&&!0!==t.hasInitialized){var e,o="",s=A(t),a=A.metadata;t.hasInitialized=!1,t.isProcessing=!0,t.config=r,A.data(t,"tablesorter",r),L.debug(r,"core")&&(console[console.group?"group":"log"]("Initializing tablesorter v"+L.version),A.data(t,"startoveralltimer",new Date)),r.supportsDataObject=((e=A.fn.jquery.split("."))[0]=parseInt(e[0],10),1':"",d.$headers=A(A.map(d.$table.find(d.selectorHeaders),function(e,t){var r,o,s,a,n,i=A(e);if(!L.getClosest(i,"tr").hasClass(d.cssIgnoreRow))return/(th|td)/i.test(e.nodeName)||(n=L.getClosest(i,"th, td"),i.attr("data-column",n.attr("data-column"))),r=L.getColumnData(d.table,d.headers,t,!0),d.headerContent[t]=i.html(),""===d.headerTemplate||i.find("."+L.css.headerIn).length||(a=d.headerTemplate.replace(L.regex.templateContent,i.html()).replace(L.regex.templateIcon,i.find("."+L.css.icon).length?"":l),d.onRenderTemplate&&(o=d.onRenderTemplate.apply(i,[t,a]))&&"string"==typeof o&&(a=o),i.html('
'+a+"
")),d.onRenderHeader&&d.onRenderHeader.apply(i,[t,d,d.$table]),s=parseInt(i.attr("data-column"),10),e.column=s,n=L.getOrder(L.getData(i,r,"sortInitialOrder")||d.sortInitialOrder),d.sortVars[s]={count:-1,order:n?d.sortReset?[1,0,2]:[1,0]:d.sortReset?[0,1,2]:[0,1],lockedOrder:!1,sortedBy:""},void 0!==(n=L.getData(i,r,"lockedOrder")||!1)&&!1!==n&&(d.sortVars[s].lockedOrder=!0,d.sortVars[s].order=L.getOrder(n)?[1,1]:[0,0]),d.headerList[t]=e,i.addClass(L.css.header+" "+d.cssHeader),L.getClosest(i,"tr").addClass(L.css.headerRow+" "+d.cssHeaderRow).attr("role","row"),d.tabIndex&&i.attr("tabindex",0),e})),d.$headerIndexed=[],r=0;r'),t=n.$table.width(),s=(o=n.$tbodies.find("tr:first").children(":visible")).length,a=0;a").css("width",r));n.$table.prepend(i)}},getData:function(e,t,r){var o,s,a="",n=A(e);return n.length?(o=!!A.metadata&&n.metadata(),s=" "+(n.attr("class")||""),void 0!==n.data(r)||void 0!==n.data(r.toLowerCase())?a+=n.data(r)||n.data(r.toLowerCase()):o&&void 0!==o[r]?a+=o[r]:t&&void 0!==t[r]?a+=t[r]:" "!==s&&s.match(" "+r+"-")&&(a=s.match(new RegExp("\\s"+r+"-([\\w-]+)"))[1]||""),A.trim(a)):""},getColumnData:function(e,t,r,o,s){if("object"!=typeof t||null===t)return t;var a,n=(e=A(e)[0]).config,i=s||n.$headers,d=n.$headerIndexed&&n.$headerIndexed[r]||i.find('[data-column="'+r+'"]:last');if(void 0!==t[r])return o?t[r]:t[i.index(d)];for(a in t)if("string"==typeof a&&d.filter(a).add(d.find(a)).length)return t[a]},isProcessing:function(e,t,r){var o=(e=A(e))[0].config,s=r||e.find("."+L.css.header);t?(void 0!==r&&0'),A.fn.detach?t.detach():t.remove();var o=A(e).find("colgroup.tablesorter-savemyplace");t.insertAfter(o),o.remove(),e.isProcessing=!1},clearTableBody:function(e){A(e)[0].config.$tbodies.children().detach()},characterEquivalents:{a:"áàâãäąå",A:"ÁÀÂÃÄĄÅ",c:"çćč",C:"ÇĆČ",e:"éèêëěę",E:"ÉÈÊËĚĘ",i:"íìİîïı",I:"ÍÌİÎÏ",o:"óòôõöō",O:"ÓÒÔÕÖŌ",ss:"ß",SS:"ẞ",u:"úùûüů",U:"ÚÙÛÜŮ"},replaceAccents:function(e){var t,r="[",o=L.characterEquivalents;if(!L.characterRegex){for(t in L.characterRegexArray={},o)"string"==typeof t&&(r+=o[t],L.characterRegexArray[t]=new RegExp("["+o[t]+"]","g"));L.characterRegex=new RegExp(r+"]")}if(L.characterRegex.test(e))for(t in o)"string"==typeof t&&(e=e.replace(L.characterRegexArray[t],t));return e},validateOptions:function(e){var t,r,o,s,a="headers sortForce sortList sortAppend widgets".split(" "),n=e.originalSettings;if(n){for(t in L.debug(e,"core")&&(s=new Date),n)if("undefined"===(o=typeof L.defaults[t]))console.warn('Tablesorter Warning! "table.config.'+t+'" option not recognized');else if("object"===o)for(r in n[t])o=L.defaults[t]&&typeof L.defaults[t][r],A.inArray(t,a)<0&&"undefined"===o&&console.warn('Tablesorter Warning! "table.config.'+t+"."+r+'" option not recognized');L.debug(e,"core")&&console.log("validate options time:"+L.benchmark(s))}},restoreHeaders:function(e){var t,r,o=A(e)[0].config,s=o.$table.find(o.selectorHeaders),a=s.length;for(t=0;t tr").children("th, td");!1===t&&0<=A.inArray("uitheme",a.widgets)&&(s.triggerHandler("applyWidgetId",["uitheme"]),s.triggerHandler("applyWidgetId",["zebra"])),n.find("tr").not(i).remove(),o="sortReset update updateRows updateAll updateHeaders updateCell addRows updateComplete sorton appendCache updateCache applyWidgetId applyWidgets refreshWidgets removeWidget destroy mouseup mouseleave "+"keypress sortBegin sortEnd resetToLoadState ".split(" ").join(a.namespace+" "),s.removeData("tablesorter").unbind(o.replace(L.regex.spaces," ")),a.$headers.add(d).removeClass([L.css.header,a.cssHeader,a.cssAsc,a.cssDesc,L.css.sortAsc,L.css.sortDesc,L.css.sortNone].join(" ")).removeAttr("data-column").removeAttr("aria-label").attr("aria-disabled","true"),i.find(a.selectorSort).unbind("mousedown mouseup keypress ".split(" ").join(a.namespace+" ").replace(L.regex.spaces," ")),L.restoreHeaders(e),s.toggleClass(L.css.table+" "+a.tableClass+" tablesorter-"+a.theme,!1===t),s.removeClass(a.namespace.slice(1)),e.hasInitialized=!1,delete e.config.cache,"function"==typeof r&&r(e),L.debug(a,"core")&&console.log("tablesorter has been removed")}}};A.fn.tablesorter=function(t){return this.each(function(){var e=A.extend(!0,{},L.defaults,t,L.instanceMethods);e.originalSettings=t,!this.hasInitialized&&L.buildTable&&"TABLE"!==this.nodeName?L.buildTable(this,e):L.setup(this,e)})},window.console&&window.console.log||(L.logs=[],console={},console.log=console.warn=console.error=console.table=function(){var e=1 max_limit: limit = max_limit + if limit: + pagination_dict['limit'] = limit + if offset: + pagination_dict['offset'] = offset + if pagination_dict: + pagination_dict, errors = _validate(data_dict, default_pagination_schema(), context) + if errors: + raise ValidationError(errors) - # Validate pagination - pagination_dict = {'limit': limit, 'offset': offset} - pagination_dict, errors = _validate(data_dict, logic.schema.default_pagination_schema(), context) - if errors: - raise ValidationError(errors) - + # Determine sort field and order if sort: sort_order = 'asc' if 'asc' in sort else 'desc' sort_field_name = sort.strip().split(' ')[0] @@ -411,26 +420,46 @@ def _custom_group_or_org_list(context, data_dict, is_sysadmin, is_org=True): sort_field_name = 'created' q = data_dict.get('q', '').strip() + publisher_country = None publisher_iati_id = None + is_approval_needed = False name_query = None - if 'publisher_country' in q or 'publisher_iati_id' in q: + if 'publisher_country' in q or 'publisher_iati_id' in q or 'approval_needed' in q: filter_args = parse_qs(q) publisher_country = filter_args.get("publisher_country", [None])[0] publisher_iati_id = filter_args.get("publisher_iati_id", [None])[0] + if filter_args.get("state", [None])[0] == 'approval_needed': + is_approval_needed = True else: name_query = q query = model.Session.query(Group.id, Group.name, Group.title, Group.created) - query = query.filter(Group.state == 'active', Group.is_organization == is_org) + + if is_approval_needed: + query = query.filter(Group.state == 'approval_needed', Group.is_organization == is_org) + elif is_sysadmin: + query = query.filter( + or_(Group.state == 'active', Group.state == 'approval_needed'), + Group.is_organization == is_org) + else: + query = query.filter(Group.state == 'active', Group.is_organization == is_org) + query = query.filter(Group.type == group_type) if name_query: general_search_pattern = f"%{name_query}%" - query = query.filter( + query = query.outerjoin( + model.GroupExtra, + and_( + model.GroupExtra.group_id == model.Group.id, + model.GroupExtra.key == 'publisher_iati_id' + ) + ).filter( or_( model.Group.name.ilike(general_search_pattern), model.Group.title.ilike(general_search_pattern), + model.GroupExtra.value.ilike(general_search_pattern) ) ) @@ -456,12 +485,13 @@ def _custom_group_or_org_list(context, data_dict, is_sysadmin, is_org=True): ), isouter=True, ).filter( - GroupExtra.value.ilike(f"%{publisher_iati_id}%") + GroupExtra.value.like(f"%{publisher_iati_id}%") ) + extra_alias = None if sort_field_name in group_extra_sort_fields: extra_alias = sa.alias(GroupExtra, name=f"group_extra_{sort_field_name}") - query = query.join( + query = query.outerjoin( extra_alias, and_( extra_alias.c.group_id == Group.id, @@ -469,24 +499,44 @@ def _custom_group_or_org_list(context, data_dict, is_sysadmin, is_org=True): ) ) - if sort_field_name in group_extra_sort_fields: - if sort_order == 'asc': - query = query.order_by(sa.asc(extra_alias.c.value)) + if sort_field_name == 'publisher_organization_type': + query = query.add_columns(sa.case( + [(extra_alias.c.value == code, sa.literal(desc)) for code, desc in lists.ORGANIZATION_TYPES], + else_=extra_alias.c.value).label('organization_type_description')) + + if sort_order == 'asc': + query = query.order_by(sa.asc('organization_type_description')) + else: + query = query.order_by(sa.desc('organization_type_description')) + elif sort_field_name == 'publisher_country': + query = query.add_columns(sa.case( + [(extra_alias.c.value == code, sa.literal(name)) for code, name in COUNTRIES], + else_=extra_alias.c.value).label('country_name')) + + if sort_order == 'asc': + query = query.order_by(sa.asc('country_name')) + else: + query = query.order_by(sa.desc('country_name')) else: - query = query.order_by(sa.desc(extra_alias.c.value)) + if sort_order == 'asc': + query = query.order_by(sa.asc(extra_alias.c.value)) + else: + query = query.order_by(sa.desc(extra_alias.c.value)) else: if sort_field_name == 'name': - query = query.order_by(sa.asc(Group.name) if sort_order == 'asc' else sa.desc(Group.name)) + query = query.order_by(sa.asc(Group.title) if sort_order == 'asc' else sa.desc(Group.title)) elif sort_field_name == 'created': query = query.order_by(sa.asc(Group.created) if sort_order == 'asc' else sa.desc(Group.created)) else: query = query.order_by(sa.asc(Group.title) if sort_order == 'asc' else sa.desc(Group.title)) + total_count = query.count() + if limit: query = query.limit(int(limit)) if offset: query = query.offset(int(offset)) - + print(query) groups = query.distinct().all() all_fields = asbool(data_dict.get('all_fields', False)) @@ -500,12 +550,26 @@ def _custom_group_or_org_list(context, data_dict, is_sysadmin, is_org=True): } org_all_fields = get_action(action)(context, item_data_dict) org_all_fields['created'] = group[3].date() + del org_all_fields['users'] + del org_all_fields['tags'] + del org_all_fields['groups'] group_list.append(org_all_fields) else: ref_group_by = 'id' if context.get('api_version', 1) == 2 else 'name' group_list = [getattr(group, ref_group_by) for group in groups] - return group_list + page = int(int(offset) // int(limit)) + 1 + items_per_page = int(limit) + + custom_pagenation = Page( + collection=group_list, + page=page, + url=custom_pager_url, + items_per_page=items_per_page, + item_count=total_count + ) + + return group_list, custom_pagenation def _approval_needed(context, data_dict, is_org=False): model = context['model'] diff --git a/ckanext/iati/theme/templates/organization/index.html b/ckanext/iati/theme/templates/organization/index.html index 0023cc4..882a128 100644 --- a/ckanext/iati/theme/templates/organization/index.html +++ b/ckanext/iati/theme/templates/organization/index.html @@ -54,7 +54,7 @@ sorting=[(_('Created Descending'), 'created desc'), (_('Created Ascending'), 'created asc'), (_('Name Ascending'), 'name asc'), (_('Name Descending'), 'name desc'), (_('IATI ID Ascending'), 'publisher_iati_id asc'), (_('IATI ID Descending'), 'publisher_iati_id desc'), - (_('Organization Type Ascending'), 'publisher_organization_type asc'), (_('publisher_organization_type Descending'), 'name desc'), + (_('Organization Type Ascending'), 'publisher_organization_type asc'), (_('Organization Type Descending'), 'publisher_organization_type desc'), (_('Country Ascending'), 'publisher_country asc'), (_('Country Descending'), 'publisher_country desc'), ] %} diff --git a/ckanext/iati/theme/templates/organization/snippets/organization_list_ids.html b/ckanext/iati/theme/templates/organization/snippets/organization_list_ids.html index 9df28fe..272010f 100644 --- a/ckanext/iati/theme/templates/organization/snippets/organization_list_ids.html +++ b/ckanext/iati/theme/templates/organization/snippets/organization_list_ids.html @@ -32,7 +32,7 @@ {% set extra_fields = h.get_publisher_obj_extra_fields_pub_ids(organization) %} {% if organization.title %} - {{ h.normalize_publisher_name(organization.title) }} + {{ organization.title }} {% else %} {{ h.normalize_publisher_name(organization.name) }} {% endif %}