From 9ecbde50349d36174e132b6bca61d8e66eb92692 Mon Sep 17 00:00:00 2001 From: Ian Murray Date: Mon, 12 Mar 2012 18:39:52 +0000 Subject: [PATCH 01/12] [release-v1.6.1][branch] Created v1.6.1 branch --- ckan/__init__.py | 2 +- pip-requirements.txt | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ckan/__init__.py b/ckan/__init__.py index 9bdf93a52a7..b4333195546 100644 --- a/ckan/__init__.py +++ b/ckan/__init__.py @@ -1,4 +1,4 @@ -__version__ = '1.6.1a' +__version__ = '1.6.1b' __description__ = 'Comprehensive Knowledge Archive Network (CKAN) Software' __long_description__ = \ '''CKAN software provides a hub for datasets. The flagship site running CKAN diff --git a/pip-requirements.txt b/pip-requirements.txt index 9ff9d104906..c0a29fcb3f2 100644 --- a/pip-requirements.txt +++ b/pip-requirements.txt @@ -5,11 +5,11 @@ # # pip install --ignore-installed -r pip-requirements.txt --e git+https://github.com/okfn/ckan@master#egg=ckan +-e git+https://github.com/okfn/ckan@release-v1.6#egg=ckan # CKAN dependencies --r https://github.com/okfn/ckan/raw/master/requires/lucid_conflict.txt --r https://github.com/okfn/ckan/raw/master/requires/lucid_present.txt --r https://github.com/okfn/ckan/raw/master/requires/lucid_missing.txt +-r https://github.com/okfn/ckan/raw/release-v1.6/requires/lucid_conflict.txt +-r https://github.com/okfn/ckan/raw/release-v1.6/requires/lucid_present.txt +-r https://github.com/okfn/ckan/raw/release-v1.6/requires/lucid_missing.txt # NOTE: Developers, please do not edit this file. Changes should go in the # appropriate files in the `requires' directory. From 453e499c51464dacb6a65c6a6f1ef0c06d854166 Mon Sep 17 00:00:00 2001 From: icmurray Date: Mon, 12 Mar 2012 20:27:44 +0000 Subject: [PATCH 02/12] [release-v1.6.1][pip-requirements] Fixed silly mistake. --- pip-requirements.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pip-requirements.txt b/pip-requirements.txt index c0a29fcb3f2..4460f149f3e 100644 --- a/pip-requirements.txt +++ b/pip-requirements.txt @@ -5,11 +5,11 @@ # # pip install --ignore-installed -r pip-requirements.txt --e git+https://github.com/okfn/ckan@release-v1.6#egg=ckan +-e git+https://github.com/okfn/ckan@release-v1.6.1#egg=ckan # CKAN dependencies --r https://github.com/okfn/ckan/raw/release-v1.6/requires/lucid_conflict.txt --r https://github.com/okfn/ckan/raw/release-v1.6/requires/lucid_present.txt --r https://github.com/okfn/ckan/raw/release-v1.6/requires/lucid_missing.txt +-r https://github.com/okfn/ckan/raw/release-v1.6.1/requires/lucid_conflict.txt +-r https://github.com/okfn/ckan/raw/release-v1.6.1/requires/lucid_present.txt +-r https://github.com/okfn/ckan/raw/release-v1.6.1/requires/lucid_missing.txt # NOTE: Developers, please do not edit this file. Changes should go in the # appropriate files in the `requires' directory. From fac91e5ee0de845050c0effd06a68bb0885ad1f8 Mon Sep 17 00:00:00 2001 From: Ross Jones Date: Tue, 13 Mar 2012 08:39:38 +0000 Subject: [PATCH 03/12] Minor fix removing merge markers in internal plugin --- ckanext/publisher_form/forms.py | 35 --------------------------------- 1 file changed, 35 deletions(-) diff --git a/ckanext/publisher_form/forms.py b/ckanext/publisher_form/forms.py index e2d339a1e09..aecfbe880ed 100644 --- a/ckanext/publisher_form/forms.py +++ b/ckanext/publisher_form/forms.py @@ -112,23 +112,6 @@ def setup_template_variables(self, context, data_dict): use the available groups for the current user, but should be optional in case this is a top level group """ -<<<<<<< HEAD - c.body_class = "group edit" - c.is_sysadmin = Authorizer().is_sysadmin(c.user) - if 'group' in context: - group = context['group'] - - try: - check_access('group_update', context) - c.is_superuser_or_groupadmin = True - except NotAuthorized: - c.is_superuser_or_groupadmin = False - - c.possible_parents = model.Session.query(model.Group).\ - filter(model.Group.state == 'active').\ - filter(model.Group.type == 'publisher').\ - filter(model.Group.name != group.id ).order_by(model.Group.title).all() -======= c.user_groups = c.userobj.get_groups('publisher') local_ctx = {'model': model, 'session': model.Session, 'user': c.user or c.author} @@ -143,23 +126,13 @@ def setup_template_variables(self, context, data_dict): group = context['group'] # Only show possible groups where the current user is a member c.possible_parents = c.userobj.get_groups('publisher', 'admin') ->>>>>>> feature-2211-publishers c.parent = None grps = group.get_groups('publisher') if grps: c.parent = grps[0] -<<<<<<< HEAD - c.users = group.members_of_type(model.User) - - -======= - c.users = group.members_of_type(model.User) - - ->>>>>>> feature-2211-publishers class PublisherDatasetForm(SingletonPlugin): """ This plugin implements a new publisher form for cases where we @@ -221,10 +194,6 @@ def setup_template_variables(self, context, data_dict=None): c.resource_columns = model.Resource.get_columns() c.groups_available = c.userobj.get_groups('publisher') if c.userobj else [] -<<<<<<< HEAD - -======= ->>>>>>> feature-2211-publishers ## This is messy as auths take domain object not data_dict pkg = context.get('package') or c.pkg if pkg: @@ -238,16 +207,12 @@ def form_to_db_schema(self): Returns the schema for mapping package data from a form to a format suitable for the database. """ -<<<<<<< HEAD - return package_form_schema() -======= schema = package_form_schema() schema['groups'] = { 'name': [not_empty, val.group_id_or_name_exists, unicode], 'id': [ignore_missing, unicode], } return schema ->>>>>>> feature-2211-publishers def db_to_form_schema(data): """ From 2e5f59e32ed73a615cc9b46d1d71ca3e8ceb3613 Mon Sep 17 00:00:00 2001 From: Ross Jones Date: Tue, 13 Mar 2012 10:54:47 +0000 Subject: [PATCH 04/12] [xs] Small functional test fix --- ckan/tests/functional/test_group.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ckan/tests/functional/test_group.py b/ckan/tests/functional/test_group.py index 6e6f2a071d7..46922435e6c 100644 --- a/ckan/tests/functional/test_group.py +++ b/ckan/tests/functional/test_group.py @@ -67,7 +67,7 @@ def test_mainmenu(self): assert 'Groups' in res, res assert 'Groups' in res, res res = res.click(href='/group', index=0) - assert 'Groups of' in res, res + assert "Dave's books" in res, res def test_index(self): offset = url_for(controller='group', action='index') From bd6b2657ec9a760e2e1e9c66e5f002b8af77c7bc Mon Sep 17 00:00:00 2001 From: Ross Jones Date: Tue, 13 Mar 2012 12:16:34 +0000 Subject: [PATCH 05/12] [2228] Allows IGroupForm implementations to override the outer templates used for index/new/read --- ckan/controllers/group.py | 26 ++++- ckan/controllers/package.py | 54 +++++++---- ckan/lib/plugins.py | 64 +++++++++++++ ckan/plugins/interfaces.py | 94 +++++++++++++++---- ckanext/publisher_form/forms.py | 36 +++++++ .../templates/publisher_index.html | 24 +++++ .../templates/publisher_layout.html | 50 ++++++++++ .../templates/publisher_new.html | 14 +++ .../templates/publisher_read.html | 91 ++++++++++++++++++ 9 files changed, 411 insertions(+), 42 deletions(-) create mode 100644 ckanext/publisher_form/templates/publisher_index.html create mode 100644 ckanext/publisher_form/templates/publisher_layout.html create mode 100644 ckanext/publisher_form/templates/publisher_new.html create mode 100644 ckanext/publisher_form/templates/publisher_read.html diff --git a/ckan/controllers/group.py b/ckan/controllers/group.py index b7f8efe2413..d9ae201f623 100644 --- a/ckan/controllers/group.py +++ b/ckan/controllers/group.py @@ -36,6 +36,24 @@ def _db_to_form_schema(self, group_type=None): def _setup_template_variables(self, context, data_dict, group_type=None): return lookup_group_plugin(group_type).setup_template_variables(context,data_dict) + def _new_template(self): + from ckan.lib.helpers import default_group_type + return lookup_group_plugin(default_group_type()).new_template() + + def _index_template(self): + from ckan.lib.helpers import default_group_type + return lookup_group_plugin(default_group_type()).index_template() + + def _search_template(self): + from ckan.lib.helpers import default_group_type + return lookup_group_plugin(default_group_type()).search_template() + + def _read_template(self, group_type): + return lookup_group_plugin(group_type).read_template() + + def _history_template(self, group_type): + return lookup_group_plugin(group_type).history_template() + ## end hooks def index(self): @@ -58,7 +76,7 @@ def index(self): url=h.pager_url, items_per_page=20 ) - return render('group/index.html') + return render( self._index_template() ) def read(self, id): @@ -170,7 +188,7 @@ def pager_url(q=None, page=None): ckan.logic.action.get.group_activity_list_html(context, {'id': c.group_dict['id']}) - return render('group/read.html') + return render( self._read_template(c.group_dict['type']) ) def new(self, data=None, errors=None, error_summary=None): group_type = request.path.strip('/').split('/')[0] @@ -198,7 +216,7 @@ def new(self, data=None, errors=None, error_summary=None): self._setup_template_variables(context,data) c.form = render(self._group_form(group_type=group_type), extra_vars=vars) - return render('group/new.html') + return render(self._new_template()) def edit(self, id, data=None, errors=None, error_summary=None): group_type = self._get_group_type(id.split('@')[0]) @@ -383,7 +401,7 @@ def history(self, id): ) feed.content_type = 'application/atom+xml' return feed.writeString('utf-8') - return render('group/history.html') + return render( self._history_template(c.group_dict['type']) ) def _render_edit_form(self, fs): # errors arrive in c.error and fs.errors diff --git a/ckan/controllers/package.py b/ckan/controllers/package.py index ec055e6d64f..6ac1db2a38d 100644 --- a/ckan/controllers/package.py +++ b/ckan/controllers/package.py @@ -44,7 +44,7 @@ def search_url(params): class PackageController(BaseController): - def _package_form(self, package_type=None): + def _package_form(self, package_type=None): return lookup_package_plugin(package_type).package_form() def _form_to_db_schema(self, package_type=None): @@ -63,6 +63,20 @@ def _check_data_dict(self, data_dict, package_type=None): def _setup_template_variables(self, context, data_dict, package_type=None): return lookup_package_plugin(package_type).setup_template_variables(context, data_dict) + + def _index_template(self, package_type): + return lookup_package_plugin(package_type).index_template() + + def _search_template(self, package_type): + return lookup_package_plugin(package_type).search_template() + + def _read_template(self, package_type): + return lookup_package_plugin(package_type).read_template() + + def _history_template(self, package_type): + return lookup_package_plugin(package_type).history_template() + + authorizer = ckan.authz.Authorizer() def search(self): @@ -83,21 +97,21 @@ def search(self): # most search operations should reset the page counter: params_nopage = [(k, v) for k,v in request.params.items() if k != 'page'] - + def drill_down_url(**by): params = list(params_nopage) params.extend(by.items()) return search_url(set(params)) - - c.drill_down_url = drill_down_url - + + c.drill_down_url = drill_down_url + def remove_field(key, value): params = list(params_nopage) params.remove((key, value)) return search_url(params) c.remove_field = remove_field - + def pager_url(q=None, page=None): params = list(params_nopage) params.append(('page', page)) @@ -144,7 +158,7 @@ def pager_url(q=None, page=None): c.query_error = True c.facets = {} c.page = h.Page(collection=[]) - + return render('package/search.html') @@ -171,7 +185,7 @@ def read(self, id): abort(400, _('Invalid revision format: %r') % e.args) elif len(split) > 2: abort(400, _('Invalid revision format: %r') % 'Too many "@" symbols') - + #check if package exists try: c.pkg_dict = get_action('package_show')(context, data_dict) @@ -181,7 +195,7 @@ def read(self, id): abort(404, _('Dataset not found')) except NotAuthorized: abort(401, _('Unauthorized to read package %s') % id) - + #set a cookie so we know whether to display the welcome message c.hide_welcome_message = bool(request.cookies.get('hide_welcome_message', False)) response.set_cookie('hide_welcome_message', '1', max_age=3600) #(make cross-site?) @@ -199,7 +213,7 @@ def read(self, id): if config.get('rdf_packages'): accept_header = request.headers.get('Accept', '*/*') for content_type, exts in negotiate(autoneg_cfg, accept_header): - if "html" not in exts: + if "html" not in exts: rdf_url = '%s%s.%s' % (config['rdf_packages'], c.pkg.id, exts[0]) redirect(rdf_url, code=303) break @@ -300,11 +314,11 @@ def history(self, id): return render('package/history.html') def new(self, data=None, errors=None, error_summary=None): - + package_type = request.path.strip('/').split('/')[0] if package_type == 'group': package_type = None - + context = {'model': model, 'session': model.Session, 'user': c.user or c.author, 'extras_as_string': True, 'save': 'save' in request.params,} @@ -321,7 +335,7 @@ def new(self, data=None, errors=None, error_summary=None): data = data or clean_dict(unflatten(tuplize_dict(parse_params( request.params, ignore_keys=[CACHE_PARAMETER])))) - c.pkg_json = json.dumps(data) + c.pkg_json = json.dumps(data) errors = errors or {} error_summary = error_summary or {} @@ -438,22 +452,22 @@ def history_ajax(self, id): current_approved, approved = True, True else: current_approved = False - + data.append({'revision_id': revision['id'], 'message': revision['message'], 'timestamp': revision['timestamp'], 'author': revision['author'], 'approved': bool(revision['approved_timestamp']), 'current_approved': current_approved}) - + response.headers['Content-Type'] = 'application/json;charset=utf-8' return json.dumps(data) def _get_package_type(self, id): """ - Given the id of a package it determines the plugin to load + Given the id of a package it determines the plugin to load based on the package's type name (type). The plugin found - will be returned, or None if there is no plugin associated with + will be returned, or None if there is no plugin associated with the type. Uses a minimal context to do so. The main use of this method @@ -538,8 +552,8 @@ def _form_save_redirect(self, pkgname, action): url = url.replace('', pkgname) else: url = h.url_for(controller='package', action='read', id=pkgname) - redirect(url) - + redirect(url) + def _adjust_license_id_options(self, pkg, fs): options = fs.license_id.render_opts['options'] is_included = False @@ -574,7 +588,7 @@ def authz(self, id): def autocomplete(self): # DEPRECATED in favour of /api/2/util/dataset/autocomplete q = unicode(request.params.get('q', '')) - if not len(q): + if not len(q): return '' context = {'model': model, 'session': model.Session, diff --git a/ckan/lib/plugins.py b/ckan/lib/plugins.py index 089c1b3fd31..1a46c39c482 100644 --- a/ckan/lib/plugins.py +++ b/ckan/lib/plugins.py @@ -169,6 +169,35 @@ class DefaultDatasetForm(object): don't want this being registered. """ + def index_template(self): + """ + Returns a string representing the location of the template to be + rendered for the index page + """ + return '' + + def search_template(self): + """ + Returns a string representing the location of the template to be + rendered for the search page (if present) + """ + return 'package/search.html' + + def read_template(self): + """ + Returns a string representing the location of the template to be + rendered for the read page + """ + return 'package/read.html' + + def history_template(self): + """ + Returns a string representing the location of the template to be + rendered for the history page + """ + return 'package/history.html' + + def package_form(self): return 'package/new_package_form.html' @@ -264,6 +293,41 @@ class DefaultGroupForm(object): Note - this isn't a plugin implementation. This is deliberate, as we don't want this being registered. """ + def new_template(self): + """ + Returns a string representing the location of the template to be + rendered for the 'new' page + """ + return 'group/new.html' + + def index_template(self): + """ + Returns a string representing the location of the template to be + rendered for the index page + """ + return 'group/index.html' + + def search_template(self): + """ + Returns a string representing the location of the template to be + rendered for the search page (if present) + """ + return 'group/search.html' + + def read_template(self): + """ + Returns a string representing the location of the template to be + rendered for the read page + """ + return 'group/read.html' + + def history_template(self): + """ + Returns a string representing the location of the template to be + rendered for the read page + """ + return 'group/history.html' + def group_form(self): return 'group/new_group_form.html' diff --git a/ckan/plugins/interfaces.py b/ckan/plugins/interfaces.py index aa697d9aa33..546e2021026 100644 --- a/ckan/plugins/interfaces.py +++ b/ckan/plugins/interfaces.py @@ -9,7 +9,7 @@ 'IMapper', 'ISession', 'IMiddleware', 'IAuthFunctions', - 'IDomainObjectModification', 'IGroupController', + 'IDomainObjectModification', 'IGroupController', 'IPackageController', 'IPluginObserver', 'IConfigurable', 'IConfigurer', 'IAuthorizer', 'IActions', 'IResourceUrlChange', 'IDatasetForm', @@ -78,7 +78,7 @@ def before_map(self, map): def after_map(self, map): """ - Called after routes map is set up. ``after_map`` can be used to add fall-back handlers. + Called after routes map is set up. ``after_map`` can be used to add fall-back handlers. :param map: Routes map object :returns: Modified version of the map object @@ -119,12 +119,12 @@ def after_insert(self, mapper, connection, instance): """ Receive an object instance after that instance is INSERTed. """ - + def after_update(self, mapper, connection, instance): """ Receive an object instance after that instance is UPDATEed. """ - + def after_delete(self, mapper, connection, instance): """ Receive an object instance after that instance is DELETEed. @@ -183,10 +183,10 @@ def notify(self, resource): class IGroupController(Interface): """ - Hook into the Group controller. These will + Hook into the Group controller. These will usually be called just before committing or returning the - respective object, i.e. all validation, synchronization - and authorization setup are complete. + respective object, i.e. all validation, synchronization + and authorization setup are complete. """ def read(self, entity): @@ -200,7 +200,7 @@ def edit(self, entity): def authz_add_role(self, object_role): pass - + def authz_remove_role(self, object_role): pass @@ -231,7 +231,7 @@ def edit(self, entity): def authz_add_role(self, object_role): pass - + def authz_remove_role(self, object_role): pass @@ -284,7 +284,7 @@ def before_view(self, pkg_dict): passed will be the one that gets sent to the template. ''' return pkg_dict - + class IPluginObserver(Interface): """ @@ -315,26 +315,26 @@ def after_unload(self, service): This method is passed the instantiated service object. """ -class IConfigurable(Interface): +class IConfigurable(Interface): """ Pass configuration to plugins and extensions """ - + def configure(self, config): """ Called by load_environment """ -class IConfigurer(Interface): +class IConfigurer(Interface): """ Configure CKAN (pylons) environment via the ``pylons.config`` object """ - + def update_config(self, config): """ Called by load_environment at earliest point when config is available to plugins. The config should be updated in place. - + :param config: ``pylons.config`` object """ @@ -364,14 +364,14 @@ def is_authorized(self, username, action, domain_obj): Should return True or False. A value of False will allow other Authorizers to run; True will shortcircuit and return. """ - + class IActions(Interface): """ Allow adding of actions to the logic layer. """ def get_actions(self): """ - Should return a dict, the keys being the name of the logic + Should return a dict, the keys being the name of the logic function and the values being the functions themselves. """ @@ -442,6 +442,31 @@ def package_types(self): ##### Hooks for customising the PackageController's behaviour ##### ##### TODO: flesh out the docstrings a little more. ##### + def index_template(self): + """ + Returns a string representing the location of the template to be + rendered for the index page + """ + + def search_template(self): + """ + Returns a string representing the location of the template to be + rendered for the search page (if present) + """ + + def read_template(self): + """ + Returns a string representing the location of the template to be + rendered for the read page + """ + + def history_template(self): + """ + Returns a string representing the location of the template to be + rendered for the history page + """ + + def package_form(self): """ Returns a string representing the location of the template to be @@ -532,7 +557,40 @@ def group_types(self): ##### Hooks for customising the PackageController's behaviour ##### ##### TODO: flesh out the docstrings a little more. ##### - + def new_template(self): + """ + Returns a string representing the location of the template to be + rendered for the 'new' page. Uses the default_group_type configuration + option to determine which plugin to use the template from. + """ + + def index_template(self): + """ + Returns a string representing the location of the template to be + rendered for the index page. Uses the default_group_type configuration + option to determine which plugin to use the template from. + """ + + def search_template(self): + """ + Returns a string representing the location of the template to be + rendered for the search page (if present). + """ + + def read_template(self): + """ + Returns a string representing the location of the template to be + rendered for the read page + """ + + def history_template(self): + """ + Returns a string representing the location of the template to be + rendered for the history page + """ + + + def package_form(self): """ Returns a string representing the location of the template to be diff --git a/ckanext/publisher_form/forms.py b/ckanext/publisher_form/forms.py index 919127537d1..0adab6134a5 100644 --- a/ckanext/publisher_form/forms.py +++ b/ckanext/publisher_form/forms.py @@ -55,6 +55,42 @@ def update_config(self, config): # Override /group/* as the default groups urls config['ckan.default.group_type'] = 'publisher' + def new_template(self): + """ + Returns a string representing the location of the template to be + rendered for the new page + """ + return 'publisher_new.html' + + def index_template(self): + """ + Returns a string representing the location of the template to be + rendered for the index page + """ + return 'publisher_index.html' + + def search_template(self): + """ + Returns a string representing the location of the template to be + rendered for the search page (if present) + """ + return 'publisher_search.html' + + def read_template(self): + """ + Returns a string representing the location of the template to be + rendered for the read page + """ + return 'publisher_read.html' + + def history_template(self): + """ + Returns a string representing the location of the template to be + rendered for the read page + """ + return 'publisher_history.html' + + def group_form(self): """ Returns a string representing the location of the template to be diff --git a/ckanext/publisher_form/templates/publisher_index.html b/ckanext/publisher_form/templates/publisher_index.html new file mode 100644 index 00000000000..321e45197b2 --- /dev/null +++ b/ckanext/publisher_form/templates/publisher_index.html @@ -0,0 +1,24 @@ + + + Publishers of Datasets + Publishers of Datasets + + +
  • +

    What Are Publishers?

    + Whilst tags are great at collecting datasets together, there are occasions when you want to restrict users from editing a collection. A publisher can be set-up to specify which users have permission to add or remove datasets from it. +
  • +
    + + +
    + ${c.page.pager()} + ${group_list_from_dict(c.page.items)} + ${c.page.pager()} +
    + + + diff --git a/ckanext/publisher_form/templates/publisher_layout.html b/ckanext/publisher_form/templates/publisher_layout.html new file mode 100644 index 00000000000..25052d90311 --- /dev/null +++ b/ckanext/publisher_form/templates/publisher_layout.html @@ -0,0 +1,50 @@ + + + +
      +
    • ${h.subnav_named_route(c, h.icon('group') + _('View'), 'publisher_read',controller='group', action='read', id=c.group.name)}
    • +
    • ${h.subnav_named_route(c, h.icon('page_white_stack') + _('History'), 'publisher_action', controller='group', action='history', id=c.group.name)}
    • +   |   + +
    • + + ${h.subnav_named_route( c,h.icon('group_edit') + _('Edit'), 'publisher_action', action='edit', id=c.group.name )} +
    • +
    • + ${h.subnav_named_route(c, h.icon('lock') + _('Authorization'), 'publisher_action', controller='group', action='authz', id=c.group.name)} +
    • + + +
    +
      +
    • + ${h.subnav_named_route(c, h.icon('group') + _('List Publishers'), "publisher_index", action="index" )} +
    • +
    • + ${h.subnav_link(c, h.icon('group_add') + _('Login to Add a Publisher'), controller='group', action='new')} +
    • +
    +
    + + + diff --git a/ckanext/publisher_form/templates/publisher_new.html b/ckanext/publisher_form/templates/publisher_new.html new file mode 100644 index 00000000000..33c3ad863dd --- /dev/null +++ b/ckanext/publisher_form/templates/publisher_new.html @@ -0,0 +1,14 @@ + + + Add A Publisher + Add A Publisher + +
    + ${Markup(c.form)} +
    + + + + diff --git a/ckanext/publisher_form/templates/publisher_read.html b/ckanext/publisher_form/templates/publisher_read.html new file mode 100644 index 00000000000..17336960f2f --- /dev/null +++ b/ckanext/publisher_form/templates/publisher_read.html @@ -0,0 +1,91 @@ + + + + ${c.group.display_name} + ${c.group.display_name} + + + +
  • +
      + +
    • +

      Administrators

      +
        +
      • ${h.linked_user(admin)}
      • +
      +
    • +
      +
    +
  • + ${facet_sidebar('tags')} + ${facet_sidebar('res_format')} +
    + + +

    State: ${c.group['state']}

    +
    +
    + ${c.description_formatted} +
    +
    + +
    +
    +

    Datasets

    + + + ${field_list()} + +

    You searched for "${c.q}". ${c.page.item_count} datasets found.

    + ${c.page.pager()} + + +
    + + ${package.get('title') or package.get('name')} +    + + + + ${resource.get('format')} + + + +

    ${h.markdown_extract(package.notes)}

    + + + + + [Open Data] + + + + ${h.icon('lock')} Not Openly Licensed + + +
    +
    + ${c.page.pager()} +
    +
    + + + + + From 34517685918745e7c06686402ee267e0e5b78a62 Mon Sep 17 00:00:00 2001 From: Ross Jones Date: Tue, 13 Mar 2012 13:08:17 +0000 Subject: [PATCH 06/12] [2228] Removing unnecessary templates and making sure it works with both old auth and publisher auth --- ckan/lib/plugins.py | 7 ------- ckan/plugins/interfaces.py | 6 ------ ckanext/publisher_form/forms.py | 6 ------ .../publisher_form/templates/publisher_read.html | 15 ++++++++++++--- 4 files changed, 12 insertions(+), 22 deletions(-) diff --git a/ckan/lib/plugins.py b/ckan/lib/plugins.py index 1a46c39c482..e63cd5342ce 100644 --- a/ckan/lib/plugins.py +++ b/ckan/lib/plugins.py @@ -307,13 +307,6 @@ def index_template(self): """ return 'group/index.html' - def search_template(self): - """ - Returns a string representing the location of the template to be - rendered for the search page (if present) - """ - return 'group/search.html' - def read_template(self): """ Returns a string representing the location of the template to be diff --git a/ckan/plugins/interfaces.py b/ckan/plugins/interfaces.py index 546e2021026..f4fc050e0ef 100644 --- a/ckan/plugins/interfaces.py +++ b/ckan/plugins/interfaces.py @@ -571,12 +571,6 @@ def index_template(self): option to determine which plugin to use the template from. """ - def search_template(self): - """ - Returns a string representing the location of the template to be - rendered for the search page (if present). - """ - def read_template(self): """ Returns a string representing the location of the template to be diff --git a/ckanext/publisher_form/forms.py b/ckanext/publisher_form/forms.py index 0adab6134a5..672209f6b4a 100644 --- a/ckanext/publisher_form/forms.py +++ b/ckanext/publisher_form/forms.py @@ -69,12 +69,6 @@ def index_template(self): """ return 'publisher_index.html' - def search_template(self): - """ - Returns a string representing the location of the template to be - rendered for the search page (if present) - """ - return 'publisher_search.html' def read_template(self): """ diff --git a/ckanext/publisher_form/templates/publisher_read.html b/ckanext/publisher_form/templates/publisher_read.html index 17336960f2f..4002f264694 100644 --- a/ckanext/publisher_form/templates/publisher_read.html +++ b/ckanext/publisher_form/templates/publisher_read.html @@ -3,19 +3,28 @@ xmlns:xi="http://www.w3.org/2001/XInclude" py:strip=""> - + ${c.group.display_name} ${c.group.display_name} +
    • - +
    • Administrators

        -
      • ${h.linked_user(admin)}
      • +
      • ${h.linked_user(admin)}
    • From a2d653a75eaaf1b0c113625edce4d6b9a25446c1 Mon Sep 17 00:00:00 2001 From: Ross Jones Date: Tue, 13 Mar 2012 15:25:38 +0000 Subject: [PATCH 07/12] [2228] Allows IDatasetForm implementations to also override the default templates for search/comments/read etc --- ckan/controllers/package.py | 14 ++++++++------ ckan/lib/plugins.py | 14 ++++++++++---- ckan/plugins/interfaces.py | 10 ++++++++-- ckanext/test_tag_vocab_plugin.py | 15 +++++++++++++++ 4 files changed, 41 insertions(+), 12 deletions(-) diff --git a/ckan/controllers/package.py b/ckan/controllers/package.py index 6ac1db2a38d..60d3097d7fa 100644 --- a/ckan/controllers/package.py +++ b/ckan/controllers/package.py @@ -63,9 +63,11 @@ def _check_data_dict(self, data_dict, package_type=None): def _setup_template_variables(self, context, data_dict, package_type=None): return lookup_package_plugin(package_type).setup_template_variables(context, data_dict) + def _new_template(self, package_type): + return lookup_package_plugin(package_type).new_template() - def _index_template(self, package_type): - return lookup_package_plugin(package_type).index_template() + def _comments_template(self, package_type): + return lookup_package_plugin(package_type).comments_template() def _search_template(self, package_type): return lookup_package_plugin(package_type).search_template() @@ -159,7 +161,7 @@ def pager_url(q=None, page=None): c.facets = {} c.page = h.Page(collection=[]) - return render('package/search.html') + return render( self._search_template('') ) def read(self, id): @@ -219,7 +221,7 @@ def read(self, id): break PackageSaver().render_package(c.pkg_dict, context) - return render('package/read.html') + return render( self._read_template( package_type ) ) def comments(self, id): package_type = self._get_package_type(id) @@ -311,7 +313,7 @@ def history(self, id): ) feed.content_type = 'application/atom+xml' return feed.writeString('utf-8') - return render('package/history.html') + return render( self._history_template(c.pkg_dict['type'])) def new(self, data=None, errors=None, error_summary=None): @@ -350,7 +352,7 @@ def new(self, data=None, errors=None, error_summary=None): c.form = render(self.package_form, extra_vars=vars) else: c.form = render(self._package_form(package_type=package_type), extra_vars=vars) - return render('package/new.html') + return render( self._new_template('')) def edit(self, id, data=None, errors=None, error_summary=None): diff --git a/ckan/lib/plugins.py b/ckan/lib/plugins.py index e63cd5342ce..18c9594cf94 100644 --- a/ckan/lib/plugins.py +++ b/ckan/lib/plugins.py @@ -127,7 +127,7 @@ def register_group_plugins(map): # Our version of routes doesn't allow the environ to be # passed into the match call and so we have to set it on the # map instead. This looks like a threading problem waiting - # to happen but it is executed sequentially from instead the + # to happen but it is executed sequentially from inside the # routing setup map.connect('%s_index' % group_type, '/%s' % group_type, @@ -168,13 +168,19 @@ class DefaultDatasetForm(object): Note - this isn't a plugin implementation. This is deliberate, as we don't want this being registered. """ + def new_template(self): + """ + Returns a string representing the location of the template to be + rendered for the new page + """ + return 'package/new.html' - def index_template(self): + def comments_template(self): """ Returns a string representing the location of the template to be - rendered for the index page + rendered for the comments page """ - return '' + return 'package/comments.html' def search_template(self): """ diff --git a/ckan/plugins/interfaces.py b/ckan/plugins/interfaces.py index f4fc050e0ef..a04d8fdf473 100644 --- a/ckan/plugins/interfaces.py +++ b/ckan/plugins/interfaces.py @@ -442,10 +442,16 @@ def package_types(self): ##### Hooks for customising the PackageController's behaviour ##### ##### TODO: flesh out the docstrings a little more. ##### - def index_template(self): + def new_template(self): + """ + Returns a string representing the location of the template to be + rendered for the new page + """ + + def comments_template(self): """ Returns a string representing the location of the template to be - rendered for the index page + rendered for the comments page """ def search_template(self): diff --git a/ckanext/test_tag_vocab_plugin.py b/ckanext/test_tag_vocab_plugin.py index 65eea1c566a..8d88650b7bb 100644 --- a/ckanext/test_tag_vocab_plugin.py +++ b/ckanext/test_tag_vocab_plugin.py @@ -25,6 +25,21 @@ def is_fallback(self): def package_types(self): return ["mock_vocab_tags_plugin"] + def new_template(self): + return 'package/new.html' + + def comments_template(self): + return 'package/comments.html' + + def search_template(self): + return 'package/search.html' + + def read_template(self): + return 'package/read.html' + + def history_template(self): + return 'package/history.html' + def package_form(self): return 'package/new_package_form.html' From ec28b32429163c3ec034c0dbf20437d40cb5abd6 Mon Sep 17 00:00:00 2001 From: David Read Date: Tue, 13 Mar 2012 18:33:34 +0000 Subject: [PATCH 08/12] [release-v1.6][doc]: Removed merge cruft from install doc. --- doc/install-from-source.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/doc/install-from-source.rst b/doc/install-from-source.rst index 767a9e597cd..c4c50882195 100644 --- a/doc/install-from-source.rst +++ b/doc/install-from-source.rst @@ -219,7 +219,6 @@ Set appropriate values for the ``ckan.site_id`` and ``solr_url`` config variable :: -<<<<<<< HEAD ckan.site_id=my_ckan_instance solr_url=http://127.0.0.1:8983/solr From f9ea4792f24a9c3f509e806e81647737c1d8accc Mon Sep 17 00:00:00 2001 From: kindly Date: Wed, 14 Mar 2012 10:39:58 +0000 Subject: [PATCH 09/12] [#2229] cleanup plugin still some member test failures --- ckan/config/plugins.py | 65 --------------------------------- ckan/plugins/core.py | 5 ++- ckan/tests/logic/test_action.py | 28 +++++++------- 3 files changed, 16 insertions(+), 82 deletions(-) delete mode 100644 ckan/config/plugins.py diff --git a/ckan/config/plugins.py b/ckan/config/plugins.py deleted file mode 100644 index 645f3db7be5..00000000000 --- a/ckan/config/plugins.py +++ /dev/null @@ -1,65 +0,0 @@ -import logging -from pkg_resources import iter_entry_points - -log = logging.getLogger(__name__) - -# Entry point group. -GROUP_NAME = "ckan.plugins" - -class PluginException(Exception): pass - -def load_all(config): - plugins = config.get('ckan.plugins', '') - log.debug("Loading plugins: %s" % plugins) - for plugin in plugins.split(): - for entry_point in iter_entry_points(group=GROUP_NAME, name=plugin): - load(plugin, entry_point, config) - break - else: - raise PluginException("Plugin not found: %s" % plugin) - - -def load(name, entry_point, config): - log.debug("Plugin: %s", entry_point.dist) - entry_obj = entry_point.load()(config) - registry = config.get('ckan.plugin_registry', {}) - registry[entry_point] = entry_obj - config['ckan.plugin_registry'] = registry - return entry_obj - - -def find_methods(method_name): - """ For a given method name, find all plugins where that method exists and iterate over them. """ - from pylons import config - for k, v in config.get('ckan.plugin_registry', {}).items(): - if hasattr(v, method_name): - yield getattr(v, method_name) - else: - pass - #log.debug("%s has no method %s" % (k.name, method_name)) - - - -##### Pylons monkey-patch - -from pylons.wsgiapp import PylonsApp -import pkg_resources - -log.info("Monkey-patching Pylons to allow loading of controllers via entry point mechanism") - -find_controller_generic = PylonsApp.find_controller - -# This is from pylons 1.0 source, will monkey-patch into 0.9.7 -def find_controller(self, controller): - if controller in self.controller_classes: - return self.controller_classes[controller] - - # Check to see if its a dotted name - if '.' in controller or ':' in controller: - mycontroller = pkg_resources.EntryPoint.parse('x=%s' % controller).load(False) - self.controller_classes[controller] = mycontroller - return mycontroller - - return find_controller_generic(self, controller) - -PylonsApp.find_controller = find_controller diff --git a/ckan/plugins/core.py b/ckan/plugins/core.py index 8cc05d844e4..5260164f2a0 100644 --- a/ckan/plugins/core.py +++ b/ckan/plugins/core.py @@ -63,14 +63,15 @@ def _get_service(plugin): if isinstance(plugin, basestring): try: + name = plugin (plugin,) = iter_entry_points( group=PLUGINS_ENTRY_POINT_GROUP, - name=plugin + name=name ) except ValueError: raise PluginNotFoundException(plugin) - return plugin.load()() + return plugin.load()(name=name) elif isinstance(plugin, _pca_Plugin): return plugin diff --git a/ckan/tests/logic/test_action.py b/ckan/tests/logic/test_action.py index d6b15590af9..d1727552b6a 100644 --- a/ckan/tests/logic/test_action.py +++ b/ckan/tests/logic/test_action.py @@ -1296,7 +1296,7 @@ def test_28_group_package_show(self): assert group_names == set(['annakarenina', 'warandpeace']), group_names def test_29_group_package_show_pending(self): - context = {'model': model, 'session': model.Session, 'user': self.sysadmin_user.name} + context = {'model': model, 'session': model.Session, 'user': self.sysadmin_user.name, 'api_version': 2} group = { 'name': 'test_group_pending_package', 'packages': [{'id': model.Package.get('annakarenina').id}] @@ -1768,22 +1768,29 @@ def before_view(self, data_dict): return data_dict +MockPackageSearchPlugin().disable() + class TestSearchPluginInterface(WsgiAppCase): @classmethod def setup_class(cls): + MockPackageSearchPlugin().activate() + MockPackageSearchPlugin().enable() setup_test_search_index() CreateTestData.create() + MockPackageSearchPlugin().disable() @classmethod def teardown_class(cls): model.repo.rebuild_db() - def test_search_plugin_interface_search(self): - plugin = MockPackageSearchPlugin() - plugins.load(plugin) + def setup(self): + MockPackageSearchPlugin().enable() + def teardown(self): + MockPackageSearchPlugin().disable() + def test_search_plugin_interface_search(self): avoid = 'Tolstoy' search_params = '%s=1' % json.dumps({ 'q': '*:*', @@ -1797,11 +1804,8 @@ def test_search_plugin_interface_search(self): assert not avoid.lower() in result['title'].lower() assert results_dict['count'] == 1 - plugins.unload(plugin) def test_search_plugin_interface_abort(self): - plugin = MockPackageSearchPlugin() - plugins.load(plugin) search_params = '%s=1' % json.dumps({ 'q': '*:*', @@ -1814,11 +1818,9 @@ def test_search_plugin_interface_abort(self): res_dict = json.loads(res.body)['result'] assert res_dict['count'] == 0 assert len(res_dict['results']) == 0 - plugins.unload(plugin) def test_before_index(self): - plugin = MockPackageSearchPlugin() - plugins.load(plugin) + # no datasets get aaaaaaaa search_params = '%s=1' % json.dumps({ 'q': 'aaaaaaaa', @@ -1829,7 +1831,6 @@ def test_before_index(self): res_dict = json.loads(res.body)['result'] assert res_dict['count'] == 0 assert len(res_dict['results']) == 0 - plugins.unload(plugin) # all datasets should get abcabcabc search_params = '%s=1' % json.dumps({ @@ -1838,12 +1839,10 @@ def test_before_index(self): res = self.app.post('/api/action/package_search', params=search_params) res_dict = json.loads(res.body)['result'] - assert res_dict['count'] == 2 + assert res_dict['count'] == 2, res_dict['count'] assert len(res_dict['results']) == 2 def test_before_view(self): - plugin = MockPackageSearchPlugin() - plugins.load(plugin) res = self.app.get('/dataset/annakarenina') assert 'string_not_found_in_rest_of_template' in res.body @@ -1851,5 +1850,4 @@ def test_before_view(self): res = self.app.get('/dataset?q=') assert res.body.count('string_not_found_in_rest_of_template') == 2 - plugins.unload(plugin) From 1f2035ff27d83b7e661e6bf47f4f6652d8292fa0 Mon Sep 17 00:00:00 2001 From: Ross Jones Date: Wed, 14 Mar 2012 11:26:19 +0000 Subject: [PATCH 10/12] [xs] Fix for member_list logic --- ckan/logic/action/get.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ckan/logic/action/get.py b/ckan/logic/action/get.py index f5bae616a84..918ef45fdc3 100644 --- a/ckan/logic/action/get.py +++ b/ckan/logic/action/get.py @@ -124,7 +124,7 @@ def member_list(context, data_dict=None): # User must be able to update the group to remove a member from it if 'group' not in context: - context['group'] = group_id + context['group'] = model.Group.get( group_id ) check_access('group_show', context, data_dict) q = model.Session.query(model.Member).\ From 0c07d3be846777318b35c31325215dff00e99313 Mon Sep 17 00:00:00 2001 From: Ross Jones Date: Wed, 14 Mar 2012 12:26:18 +0000 Subject: [PATCH 11/12] [bug] Fixing the member tests --- ckan/logic/action/create.py | 19 +++++++++++-------- ckan/logic/action/delete.py | 6 ++---- ckan/logic/action/get.py | 5 ++--- ckan/tests/logic/test_member.py | 25 ++++++++++++++----------- 4 files changed, 29 insertions(+), 26 deletions(-) diff --git a/ckan/logic/action/create.py b/ckan/logic/action/create.py index e5dd055fade..a36547206af 100644 --- a/ckan/logic/action/create.py +++ b/ckan/logic/action/create.py @@ -174,15 +174,19 @@ def member_create(context, data_dict=None): """ model = context['model'] user = context['user'] + group = context['group'] + + rev = model.repo.new_revision() + rev.author = user + if 'message' in context: + rev.message = context['message'] + else: + rev.message = _(u'REST API: Create member object %s') % data_dict.get("name", "") - group_id = data_dict['group'] obj_id = data_dict['object'] obj_type = data_dict['object_type'] capacity = data_dict['capacity'] - if 'group' not in context: - context['group'] = group_id - # User must be able to update the group to add a member to it check_access('group_update', context, data_dict) @@ -190,15 +194,14 @@ def member_create(context, data_dict=None): member = model.Session.query(model.Member).\ filter(model.Member.table_name == obj_type).\ filter(model.Member.table_id == obj_id).\ - filter(model.Member.group_id == group_id).\ - filter(model.Member.state == "active").\ - filter(model.Member.capacity == capacity).first() + filter(model.Member.group_id == group.id).\ + filter(model.Member.state == "active").first() if member: member.capacity = capacity else: member = model.Member(table_name = obj_type, table_id = obj_id, - group_id = group_id, + group_id = group.id, capacity=capacity) model.Session.add(member) diff --git a/ckan/logic/action/delete.py b/ckan/logic/action/delete.py index b2d75458f47..a8368ec6195 100644 --- a/ckan/logic/action/delete.py +++ b/ckan/logic/action/delete.py @@ -82,21 +82,19 @@ def member_delete(context, data_dict=None): """ model = context['model'] user = context['user'] + group = context['group'] group_id = data_dict['group'] obj_id = data_dict['object'] obj_type = data_dict['object_type'] - if 'group' not in context: - context['group'] = group_id - # User must be able to update the group to remove a member from it check_access('group_update', context, data_dict) member = model.Session.query(model.Member).\ filter(model.Member.table_name == obj_type).\ filter(model.Member.table_id == obj_id).\ - filter(model.Member.group_id == group_id).\ + filter(model.Member.group_id == group.id).\ filter(model.Member.state == "active").first() if member: member.delete() diff --git a/ckan/logic/action/get.py b/ckan/logic/action/get.py index 918ef45fdc3..bf28588a769 100644 --- a/ckan/logic/action/get.py +++ b/ckan/logic/action/get.py @@ -117,18 +117,17 @@ def member_list(context, data_dict=None): """ model = context['model'] user = context['user'] + group = context['group'] group_id = data_dict['group'] obj_type = data_dict.get('object_type', None) capacity = data_dict.get('capacity', None) # User must be able to update the group to remove a member from it - if 'group' not in context: - context['group'] = model.Group.get( group_id ) check_access('group_show', context, data_dict) q = model.Session.query(model.Member).\ - filter(model.Member.group_id == group_id).\ + filter(model.Member.group_id == group.id).\ filter(model.Member.state == "active") if obj_type: diff --git a/ckan/tests/logic/test_member.py b/ckan/tests/logic/test_member.py index dcb6e8cba73..3c7aaa5d3a5 100644 --- a/ckan/tests/logic/test_member.py +++ b/ckan/tests/logic/test_member.py @@ -9,21 +9,26 @@ def setup_class(cls): cls.username = 'testsysadmin' cls.groupname = 'david' - model.Session.remove() - CreateTestData.create() - model.Session.remove() model.repo.new_revision() + CreateTestData.create() + cls.pkgs = [ + model.Package.by_name('warandpeace'), + model.Package.by_name('annakarenina'), + ] @classmethod def teardown_class(cls): model.repo.rebuild_db() def _build_context( self, obj, obj_type, capacity='member'): + grp = model.Group.by_name(self.groupname) ctx = { 'model': model, 'session': model.Session, - 'user':self.username} + 'user':self.username, + 'group': grp, + } dd = { - 'group': self.groupname, + 'group': grp, 'object': obj, 'object_type': obj_type, 'capacity': capacity } @@ -34,17 +39,15 @@ def _add_member( self, obj, obj_type, capacity): return get_action('member_create')(ctx,dd) def test_member_add(self): - res = self._add_member( 'warandpeace', 'package', 'member') + res = self._add_member( self.pkgs[0].id, 'package', 'member') assert 'capacity' in res and res['capacity'] == u'member' - assert 'group_id' in res and res['group_id'] == u'david' def test_member_list(self): - _ = self._add_member( 'warandpeace', 'package', 'member') - _ = self._add_member( 'annakarenina', 'package', 'member') + _ = self._add_member( self.pkgs[0].id, 'package', 'member') + _ = self._add_member( self.pkgs[1].id, 'package', 'member') ctx, dd = self._build_context('','package') res = get_action('member_list')(ctx,dd) - assert res[0][0] == 'warandpeace', res - assert res[1][0] == 'annakarenina', res + assert len(res) == 2, res ctx, dd = self._build_context('','user', 'admin') res = get_action('member_list')(ctx,dd) From 949121093bc0cee0d06c0121997609892e8c7327 Mon Sep 17 00:00:00 2001 From: Ross Jones Date: Thu, 15 Mar 2012 14:07:02 +0000 Subject: [PATCH 12/12] [bug] For new/search/index determine the group/package type from the url --- ckan/controllers/group.py | 19 +++++++++---------- ckan/controllers/package.py | 7 ++++++- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/ckan/controllers/group.py b/ckan/controllers/group.py index d9ae201f623..7c8332f47dd 100644 --- a/ckan/controllers/group.py +++ b/ckan/controllers/group.py @@ -36,17 +36,13 @@ def _db_to_form_schema(self, group_type=None): def _setup_template_variables(self, context, data_dict, group_type=None): return lookup_group_plugin(group_type).setup_template_variables(context,data_dict) - def _new_template(self): + def _new_template(self,group_type): from ckan.lib.helpers import default_group_type - return lookup_group_plugin(default_group_type()).new_template() + return lookup_group_plugin(group_type).new_template() - def _index_template(self): + def _index_template(self,group_type): from ckan.lib.helpers import default_group_type - return lookup_group_plugin(default_group_type()).index_template() - - def _search_template(self): - from ckan.lib.helpers import default_group_type - return lookup_group_plugin(default_group_type()).search_template() + return lookup_group_plugin(group_type).index_template() def _read_template(self, group_type): return lookup_group_plugin(group_type).read_template() @@ -57,6 +53,9 @@ def _history_template(self, group_type): ## end hooks def index(self): + group_type = request.path.strip('/').split('/')[0] + if group_type == 'group': + group_type = None context = {'model': model, 'session': model.Session, 'user': c.user or c.author} @@ -76,7 +75,7 @@ def index(self): url=h.pager_url, items_per_page=20 ) - return render( self._index_template() ) + return render( self._index_template(group_type) ) def read(self, id): @@ -216,7 +215,7 @@ def new(self, data=None, errors=None, error_summary=None): self._setup_template_variables(context,data) c.form = render(self._group_form(group_type=group_type), extra_vars=vars) - return render(self._new_template()) + return render(self._new_template(group_type)) def edit(self, id, data=None, errors=None, error_summary=None): group_type = self._get_group_type(id.split('@')[0]) diff --git a/ckan/controllers/package.py b/ckan/controllers/package.py index 60d3097d7fa..27e39d1e50b 100644 --- a/ckan/controllers/package.py +++ b/ckan/controllers/package.py @@ -83,6 +83,11 @@ def _history_template(self, package_type): def search(self): from ckan.lib.search import SearchError + + package_type = request.path.strip('/').split('/')[0] + if package_type == 'group': + package_type = None + try: context = {'model':model,'user': c.user or c.author} check_access('site_read',context) @@ -161,7 +166,7 @@ def pager_url(q=None, page=None): c.facets = {} c.page = h.Page(collection=[]) - return render( self._search_template('') ) + return render( self._search_template(package_type) ) def read(self, id):